部分设计模式(工厂+单例+适配器+装饰+代理+观察者)
2018-02-26 11:16
323 查看
http://blog.csdn.net/a394268045/article/details/51801258
1.普通工厂设计模式
--实现同一接口的一些类,需要对这些类进行创建—》建立一个工厂类
接口:
publicinterface Sender {
publicvoid Send();
}
两个实现类:
publicclassMailSenderimplementsSender {
@Override
publicvoid Send() {
System.out.println("this is mailsender!");
}
}
publicclassSmsSenderimplementsSender {
@Override
publicvoid Send() {
System.out.println("this is sms sender!");
}
}
1.1通过传入的字符串建立对象的工厂类
publicclass SendFactory {
public Sender produce(String type) {
if ("mail".equals(type)) {
returnnew MailSender();
} elseif ("sms".equals(type)) {
returnnew SmsSender();
} else {
System.out.println("请输入正确的类型!");
returnnull;
}
}
}
1.2.创建对象时不需要提供字符串,提供方法
publicclass SendFactory {
public Sender produceMail(){
returnnew MailSender();
}
public Sender produceSms(){
returnnew SmsSender();
}
}
1.3静态工厂
将工厂方法设置为静态的,不需要创建实例
publicclass SendFactory {
publicstatic Sender produceMail(){
returnnew MailSender();
}
publicstatic Sender produceSms(){
returnnew SmsSender();
}
}
2.抽象工厂模式:
来源:类的创建依赖工厂类,如果要拓展程序,必须修改工厂类,违背了开闭原则。
则采用抽象工厂模式,创建多个工厂类,需要新的功能,直接增加新的工厂类,不需要修改之前的代码
首先,还是有一个我们将创建实例类的抽象接口publicinterface Sender { publicvoid Send();
}
其次,两个实现类publicclassMailSenderimplementsSender { @Override publicvoid Send() { System.out.println("this is mailsender!"); } } publicclassSmsSenderimplementsSender { @Override publicvoid Send() { System.out.println("this is sms sender!"); }
}
再提供工厂的接口:publicinterface Provider { public Sender produce();
}
两个工厂实现类:publicclassSendMailFactoryimplementsProvider { @Override public Sender produce(){ returnnew MailSender(); }
}
publicclassSendSmsFactoryimplementsProvider{ @Override public Sender produce() { returnnew SmsSender();
4000
} }
总结:
抽象工厂设计模式,将工厂也抽象出来,如果现在要增加一个功能,如发及时消息,则需要一个sender的实现类,同时需要一个工厂的实现类(实现provider)无需改动现有的代码。
3.单例设计模式
---保证JVM中只有该对象的一个实例存在
好处:
一些类的创建比较频繁,开销大
不使用new,降低内存的使用频率,减轻gc压力
有些类不能创建多个,如果创建多个则系统乱掉
3.1不安全的懒汉式
Public class Singleton{
Privatestatic Singleton instance = null;//延迟加载
PrivateSingleton(){};//防止被实例化
Publicstatic Singleton getInstance(){
If(instance==null){
Instance = new Singleton();
}
Return instance;
}
}
3.2饿汗式
Public class Singleton{
Privatestatic Singleton instance = new Singleton();
Private Singleton(){};//防止被实例化
Publicstatic Singleton getInstance(){
Return instance;
}
}
3.3.1同步:给getInstance加synchronize关键字,但是效率低publicstaticsynchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance;
}
3.3.2同步:只在创建对象的时候加锁publicstatic Singleton getInstance() { if (instance == null) { synchronized (instance) { //第二次判断的意义:两个线程在第一次判断后,其中一个线程new完新对象,//第二个线程执行到这里时,不会检测instance是否为null,直接new,//出现问题,所以需要第二次非空判断,保证指向的同一个实例 if (instance == null) { instance = new Singleton(); } } } return instance;
}
3.3.3同步:实现线程安全
来源:
在java指令中创建对象和赋值操作时分开进行的,instance = new Singleton(),分两步执行,jvm不能保证两个操作的先后执行顺序。可能先为singleton分配实例空间,再赋值给instance成员,再去初始化singleton实例,这样就有问题 :
a>A、B线程同时进入了第一个if判断
b>A首先进入synchronized块,由于instance为null,所以它执行instance = new Singleton();
c>由于JVM内部的优化机制,JVM先画出了一些分配给Singleton实例的空白内存,并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。
d>B进入synchronized块,由于instance此时不是null,因此它马上离开了synchronized块并将结果返回给调用该方法的程序。
e>此时B线程打算使用Singleton实例,却发现它没有被初始化,于是错误发生了。
解决:使用内部类维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就不用担心上面的问题。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题。publicclass Singleton { /* 私有构造方法,防止被实例化 */ private Singleton() { } /* 此处使用一个内部类来维护单例 */ privatestaticclass SingletonFactory { privatestatic Singleton instance = new Singleton(); } /* 获取实例 */ publicstatic Singleton getInstance() { return SingletonFactory.instance; } /* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */ public Object readResolve() { return getInstance(); }
}
在创建类的时候进行同步:
publicclass SingletonTest {
private static SingletonTest instance =null;
private SingletonTest() {
}
private static synchronized void syncInit(){
if (instance == null) {
instance = newSingletonTest();
}
}
public static SingletonTest getInstance(){
if (instance == null) {
syncInit();
}
return instance;
}
}
3.3.4 volatile
当程序在运行过程中,会将运算需要的数据从主存复制一份到CPU的高速缓存当中,那么CPU进行计算时就可以直接从它的高速缓存读取数据和向其中写入数据,当运算结束之后,再将高速缓存中的数据刷新到主存当中。举个简单的例子,比如下面的这段代码:
i= i +
1;
当线程执行这个语句时,会先从主存当中读取i的值,然后复制一份到高速缓存当中,然后CPU执行指令对i进行加1操作,然后将数据写入高速缓存,最后将高速缓存中i最新的值刷新到主存当中。
这个代码在单线程中运行是没有任何问题的,但是在多线程中运行就会有问题了。在多核CPU中,每条线程可能运行于不同的CPU中,因此每个线程运行时有自己的高速缓存(对单核CPU来说,其实也会出现这种问题,只不过是以线程调度的形式来分别执行的)。
可能存在下面一种情况:初始时,两个线程分别读取i的值存入各自所在的CPU的高速缓存当中,然后线程1进行加1操作,然后把i的最新值1写入到内存。此时线程2的高速缓存当中i的值还是0,进行加1操作之后,i的值为1,然后线程2把i的值写入内存。
最终结果i的值是1,而不是2。这就是著名的缓存一致性问题。通常称这种被多个线程访问的变量为共享变量。
可见性问题://线程1执行的代码int i = 0;i = 10; //线程2执行的代码j = i;假若执行线程1的是CPU1,执行线程2的是CPU2。由上面的分析可知,当线程1执行 i =10这句时,会先把i的初始值加载到CPU1的高速缓存中,然后赋值为10,那么在CPU1的高速缓存当中i的值变为10了,却没有立即写入到主存当中。 此时线程2执行 j = i,它会先去主存读取i的值并加载到CPU2的缓存当中,注意此时内存当中i的值还是0,那么就会使得j的值为0,而不是10. 这就是可见性问题,线程1对变量i修改了之后,线程2没有立即看到线程1修改的值。
Volatile变量具有synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现volatile变量的最新值。
当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。
---这里在声明变量时使用了volatile关键字来保证其线程间的可见性;在同步代码块中使用二次检查,以保证其不被重复实例化。集合其二者,这种实现方式既保证了其高效性,也保证了其线程安全性。
publicclass MySingleton {
//使用volatile关键字保其可见性
volatile private static MySingletoninstance = null;
private MySingleton(){}
public static MySingleton getInstance(){
try {
if(instance != null){//懒汉式
}else{
//创建实例之前可能会有一些准备性的耗时工作
Thread.sleep(300);
synchronized(MySingleton.class) {
if(instance == null){//二次检查
instance = newMySingleton();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return instance;
}
}
3.3.5静态代码块实现单例
publicclass MySingleton{
private static MySingleton instance =null;
private MySingleton(){}
static{
instance = new MySingleton();
}
public static MySingleton getInstance(){
return instance;
}
}
4.适配器模式:
目的是消除由于接口不匹配所造成的类的兼容性问题
类适配器:
核心思想就是:有一个Source类,拥有一个方法,待适配,目标接口时Targetable,通过Adapter类,将Source的功能扩展到Targetable里
抽象思维:鼠标以前的插头source,转接口adapter,要想source与adapter连接上,则adpter继承自source,adpter需要提供新的接口,则实现targetable接口。publicclassSource { publicvoid method1() { System.out.println("this is original method!"); }
}publicinterfaceTargetable { /* 与原类中的方法相同 */ publicvoid method1(); /* 新类的方法 */ publicvoid method2();
} publicclassAdapterextendsSourceimplementsTargetable { @Override publicvoid method2() { System.out.println("this is the targetable method!"); }
}
测试:Targetable target = new Adapter(); target.method1();
target.method2();
对象适配器:
基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题publicclassWrapperimplementsTargetable { private Source source; public Wrapper(Source source){ super(); this.source = source; } @Override publicvoid method2() { System.out.println("this is the targetable method!"); } @Override publicvoid method1() { source.method1(); }
}
接口适配:
我们也常会遇到这种接口中定义了太多的方法,以致于有时我们在一些实现类中并不是都需要
publicinterface Sourceable { publicvoid method1(); publicvoid method2();
}
publicabstractclassWrapper2implementsSourceable{ publicvoid method1(){} publicvoid method2(){}
} publicclassSourceSub1extendsWrapper2 { publicvoid method1(){ System.out.println("the sourceable interface's first Sub1!"); }
}
publicclassSourceSub2extendsWrapper2 { publicvoid method2(){ System.out.println("the sourceable interface's second Sub2!"); }
}
三种适配器的应用场景:
类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。
接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可
5.装饰模式:
装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。publicinterfaceSourceable { publicvoid method();
} publicclassSourceimplementsSourceable { @Override publicvoid method() { System.out.println("the original method!"); }
}
publicclassDecoratorimplementsSourceable { private Sourceable source; public Decorator(Sourceable source){ super(); this.source = source; } @Override publicvoid method() { System.out.println("before decorator!"); source.method(); System.out.println("after decorator!"); }
}
6.代理模式:
代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。再如我们有的时候打官司,我们需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们的想法
public interface Sourceable {
public void method();
} public classSource implements Sourceable {@Override public voidmethod() { System.out.println("the originalmethod!"); } } public classProxy implements Sourceable {
private Source source;
public Proxy(){
super();
this.source = new Source();
}
@Override
public void method() {
before();
source.method();
atfer();
}
private void atfer() {
System.out.println("after proxy!");
}
private void before() {
System.out.println("before proxy!");
}}
7.观察者模式:
类似于邮件订阅和RSS订阅,当我们浏览一些博客或wiki时,经常会看到RSS图标,就这的意思是,当你订阅了该文章,如果后续有更新,会及时通知你。其实,简单来讲就一句话:当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系
MySubject类就是我们的主对象,Observer1和Observer2是依赖于MySubject的对象,当MySubject变化时,Observer1和Observer2必然变化。AbstractSubject类中定义着需要监控的对象列表,可以对其进行修改:增加或删除被监控对象,且当MySubject变化时,负责通知在列表内存在的对象。
public interfaceObserver {
public void update();
}
public class Observer1 implements Observer{
@Override
public void update() {
System.out.println("observer1has received!");
}
}
public class Observer2 implements Observer{
@Override
public void update() {
System.out.println("observer2 has received!");
}
}
public interface Subject {
/*
增加观察者
*/
public void add(Observer observer);
/*
删除观察者
*/
public void del(Observer observer);
/*
通知所有的观察者
*/
public void notifyObservers();
/*
自身的操作
*/
public void operation();
}
public abstract class AbstractSubjectimplements Subject {
private Vector<Observer> vector = newVector<Observer>();
@Override
public void add(Observer observer) {
vector.add(observer);
}
@Override
public void del(Observer observer) {
vector.remove(observer);
}
@Override
public void notifyObservers() {
Enumeration<Observer> enumo = vector.elements();
while(enumo.hasMoreElements()){
enumo.nextElement().update();
}
}
}
public class MySubject extendsAbstractSubject {
@Override
public void operation() {
System.out.println("update self!");
notifyObservers();
}
}
测试:
Subject sub = new MySubject();
sub.add(new Observer1());
sub.add(new Observer2());
sub.operation();
相关文章推荐
- 设计模式---复合模式(策略-适配器-装饰者-抽象工厂-组合-观察者)
- 常用设计模式举例,观察者模式,装饰模式,工厂模式,单列模式---Head Frist 设计模式源码
- Design Patterns Simplified - Part 3 (Simple Factory)【设计模式简述--第三部分(简单工厂)】
- 23种设计模式 第三部分 关系模式(3)观察者模式
- Android 设计模式之(三)观察者,适配器,桥接,组合模式
- iOS设计模式(MVC和单例模式,门面和装饰器模式,适配器和观察者模式以及备忘录和命令模式)
- 系统架构-设计模式(适配器、观察者、代理、抽象工厂等)及架构模式(C/S、B/S、分布式、SOA、SaaS)(干货)
- iOS中的设计模式常识(适配器、策略、工厂)
- c#winform:开发多语言应用程序---多国语言本地化与设计模式的思考----观察者模式+工厂模式!
- Java基础 - 单例(饿汉、懒汉),Runtime类,Timer,线程通信,互斥锁,线程组,线程五种状态,线程池,工厂模式,GUI,适配器设计模式
- 设计模式(一) 观察者模式、装饰模式、工厂模式
- 【设计模式】工场模式 || 抽象工厂 || 观察者模式 || 代理模式
- JAVA设计模式(DESIGN PATTERNS IN JAVA)读书摘要 第1部分接口型模式——第3章 适配器(Adapter)模式
- Java设计模式, 单例模式,工厂模式,建造者模式和观察者模式
- Spring中的设计模式(工厂单例代理模板适配器)
- [零基础学JAVA]Java SE应用部分-36.反射机制与工厂设计模式 推荐
- iOS设计模式(MVC和单例模式,门面和装饰器模式,适配器和观察者模式以及备忘录和命令模式)
- ios开发中的基本设计模式(代理,观察者,MVC,单例,策略,工厂,MVVM,原型,Target-Action,通知(notification)机制)
- 设计模式之观察者模式,C++实现(上部分)
- 适配器、工厂模式、线程池、线程组、互斥锁、Timer类、Runtime类、单例设计模式(二十四)