设计模式

来源:互联网 发布:f3有刷飞控用什么软件 编辑:程序博客网 时间:2024/06/05 14:37

一、单例模式
1、饿汉模式

public class HungurySingleton{    private static final HungurySingleton singleton         = new HungurySingleton();    private HungurySingleton(){        System.out.println("singleton is create");    }    public static HungurySingleton getInstance(){        return singleton;    }    public static void otherMethod(){        System.out.println("otherMethod");    }}

缺点:无法对instance实例做延时加载。
程序启动时即初始化,即使不调用getInstance方法singleton也已经被创建出来了,上例中即使只调用otherMethod方法也会先打印singleton is create,假如构造方法内初始化的东西特别多时会影响性能。

2、懒汉模式

public class LazySingleton{    private static LazySingleton singleton;    private LazySingleton(){    }    public static LazySingleton getInstance(){        if(singleton == null){            singleton = new LazySingleton();        }        return singleton;    }}

缺点:多线程并发下无法保证实例唯一

3、懒汉线程安全模式

public class LazySafetySingleton{    private static LazySafetySingleton singleton;    private LazySafetySingleton(){    }    public static synchronized LazySafetySingleton getInstance(){        if(singleton == null){            singleton = new LazySafetySingleton();        }        return singleton;    }    或    public static LazySafetySingleton getInstance(){        synchronized(LazySafetySingleton.class){            if(singleton == null){                singleton = new LazySafetySingleton();            }        }        return singleton;    }}

缺点:每次调取都需执行同步操作,影响性能。

4、DCL双检锁模式

public class DCLSingleton{    //private static volatile DCLSingleton singleton = null;    private static DCLSingleton singleton = null;    private DCLSingleton(){    }    public static DCLSingleton getInstance(){        if(singleton == null){            synchronized(DCLSingleton.class){                if(singleton == null){                    singleton = new DCLSingleton();                }            }        }        return singleton;    }}

优点:两次检查singleton是否为空,减少同步代码块的执行次数提升性能。
缺点:new DCLSingleton()不是原子操作,JVM存在指令重排序的优化导致顺序不固定,导致线程不安全(理想顺序为 给singleton分配内存-调用构造方法初始化变量-将singleton指向内存空间。实际顺序不固定)。解决方法为将变量设为volatile类型。
volatile类型可以控制对象的唯一性,保持线程间同步,由于jvm的缓存机制,假如int i = 1;有两个子线程正在轮询使用i,假如此时线程A更改了i的值为2,那由于缓存机制,线程B还没来得及更改i的拷贝的值,所以还是1,就出现了不同步的情况,而volatile关键字就是解决这个问题,防止缓存拷贝,保持唯一性。

5、静态内部类模式

public class StaticInnerSingleton{    private StaticInnerSingleton(){}    public static StaticInnerSingleton getInstance(){        return SingleHolder.instance;    }    //私有静态内部类    private static class SingleHolder{        private static final StaticInnerSingleton instance = new StaticInnerSingleton();    }}

优点:延时加载,线程安全(通过static内部类和final声明),性能比synchronized要高

6、枚举模式

public class EnumSingleton{    private EnumSingleton(){}    public static EnumSingleton getInstance(){        return Singleton.INSTANCE.getInstance();    }    private static enum Singleton{        INSTANCE;        private EnumSingleton singleton;        //JVM会保证此方法绝对只调用一次        private Singleton(){            singleton = new EnumSingleton();        }        public EnumSingleton getInstance(){            return singleton;        }    }}

优点:延时加载,线程安全(因为JVM会保证enum不能被反射并且构造器方法只执行一次),性能比synchronized要高。

7、单例模式在Android中的应用
(1)application

public class MyApplication extends Application{    private static MyApplication instance;    @override    public void onCreate(){        super.onCreate();        instance = this;    }    public static MyApplication getInstance(){        return instance;    }}

(2)单例模式引起的内存泄漏
原因:由于单例是静态的,所以声明周期是和应用的声明周期一样长,如果引用了短生命周期的实例如activity的context的话就可能引起内存泄漏,具体可参考

http://blog.csdn.net/qq_32618417/article/details/51703414

解决方法:使用application的context或采用WeakReference弱引用包装activity的context。

(3)eventbus的坑
原因:系统恢复离开的现场,直接运行接收数据的Activity,而没有运行到发送数据的Activity组件,取不到数据,因为根本就没有数据发送。
解决方法:使用EventBus传递数据时采用onSaveInstanceState(Bundle outState)方法保存数据,使用onCreate(Bundle savedInstanceState)等待恢复取值。

二、builder模式
概念:将客户端与包含多个组成部分的复杂对象的创建过程分离。
示例1:

http://www.cnblogs.com/moonz-wu/archive/2011/01/11/1932473.html

示例2:

http://blog.csdn.net/l1028386804/article/details/45442197

三、adapter模式
适配器模式,把一个类的接口变换成客户端所期待的另一种接口,从而使原本不匹配而无法在一起工作的两个,类能够在一起工作。
1、类适配器模式

public interface Target{    void sampleOperation1();    void sampleOperation2();}public class Adaptee{    pubLic void sampleOperation1(){        System.out.println("sampleOperation1");    }}public class Adapter extends Adaptee implements Target{    override    pubLic void sampleOperation2(){        System.out.println("sampleOperation2");    }}

调用
Adapter adapter = new Adapter();
adapter.sampleOperation1();
adapter.sampleOperation2();

打印结果为:
sampleOperation1
sampleOperation2

2、对象适配器模式

public interface Target{    void sampleOperation1();    void sampleOperation2();}public class Adaptee{    pubLic void sampleOperation1(){        System.out.println("sampleOperation1");    }}public class Adapter implements Target{    private Adaptee adaptee;    public Adapter(Adaptee adaptee){        this.adaptee = adaptee;    }    override    pubLic void sampleOperation1(){        adaptee.sampleOperation1();    }    override    pubLic void sampleOperation2(){        System.out.println("sampleOperation2");    }}

3、适配器模式适用场景,可参考

http://www.cnblogs.com/lwbqqyumidi/p/3750128.html

当n个地方用到UserInfo类继而获取name和telNumber时就不用每次都写

Map<String, String> outUserInfo = oui.getUserBaseInfo();String name = outUserInfo.get("name");String telNumber = outUserInfo.get("telNumber");

了,而只需要使用UserAdapter代替UserInfo直接使用UserAdapter里的getName和getTelNumber即可。

四、装饰模式

http://www.jianshu.com/p/6dcff4449f99

另:对象适配器模式和装饰模式看起来很类似,都属于包装模式,但还是有区别的:

装饰模式:对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性。使用原来被装饰的类的一个子类的实例,把客户端的调用委派到被装饰类。

适配器模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。适配类可以根据参数返还一个合适的实例给客户端。

从定义上看装饰模式是对核心对象或者功能的扩展,适配器模式是把对象或者功能放到一个新对象中引用。举个例子,现在书城卖道德经的书,有线装版,有精装版,有日文版,有英文版,其中线装版和精装版就是装饰模式,日文版和英文版就是适配器模式,各种版本都是为迎合不同消费者的不同需求。为什么呢?因为线装版和精装版的道德经虽然包装不同,但内容相同,日文版和英文版就不同,这两个版本的内容就可能和原版的不同,文化差异嘛,翻译的内容虽来自道德经,但根据不同国家的文化,思维逻辑什么的就可能改变一些想法。

使用条件:

装饰模式一般在下列情况使用:需要扩展一个类的功能或者给你个类增加附加责任;需要动态的给一个对象增加功能,这些功能可以再动态的撤销;需要增加有一些基本功能的排列组合而产生非常大量的功能,从而使得继承关系变得不现实。

适配器模式一般使用的情况包括:系统需要使用现有的类,但此类已经不符合系统的需要;

想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的的类一起工作。适配器模式在系统升级的时候使用的频率很高,对旧系统的一些功能方法在新系统中引用。

五、外观模式(了解)

http://www.jianshu.com/p/2a0b6255222e

六、组合模式(了解)

http://www.jianshu.com/p/ec69c4b8b721

七、策略模式
实现同一个功能有很多不停的算法和策略,然后根据实际情况来选择不同的算法和策略。
一般的做法是在一个类里写不同的方法,然后根据实际情况用一连串的if-else或switch来选择对应的方法。这种方法多了后,这个类会变得臃肿,难以修改。
所以如果把不同的策略抽象出来,提供一个统一的接口,为每一个策略写一个实现类,这样客户端就能通过调用接口的不同的实现类来动态替换策略。这就是策略模式。

http://www.jianshu.com/p/baf752ed01d0

八、模板模式

http://www.jianshu.com/p/6a93a9980fa9

九、观察者模式
建议使用vector或CopyOnWriteArrayList代替list存储被观察者对象的集合,线程安全。

http://www.jianshu.com/p/316147958b67

事件分发两个问题:
1、viewgroup中可能有多个childview,如何判断应该分配给哪一个?
遍历childview,手指触摸的点属于哪个childview就分配给这个childview。
2、当该点的childview有重叠时该如何分配?
一般会分配到上层的那个childview。

dispatchTouchEvent:在viewgroup中用作分发事件,通过是否拦截来判定分发到哪里;在view中用作分发四个事件:onClickListener、onTouchListener、onLongClickListener、onTouchEvent(view自身处理)。而事件调用顺序为onTouchListener-onTouchEvent-onLongClickListener-onClickListener,事件层层传递,直到被消费。