2018年4月

先写工厂模式之前,说说一个有趣的观点。曾经彩笔的我,刚踏上程序员之路的时候,只会单例、工厂模式。某次,在和某人讨论的时候,某人直接说工厂模式不需要,存在是没意义的,于是这段话就在我幼小的心灵中种下了一颗种子(主要是当时懒,觉得反驳不来,于是忘记了)。最近重新的梳理的时候,又想起了这个事,于是搜索了下,发现b乎上有大牛总结的很好,直接拖过来。

JAVA工厂方法的疑问(为何要创建工厂类或者工厂接口)? - 胖胖的回答 - 知乎

大意就是工厂模式的关键是模式,属于创建者模式。而创造者模式,最大的特征就是将“定义过程”和“实例化过程”分离。如果只是简单的用传参来重载方法完成,一旦功能变得复杂,代码重复率就会越来越多,代码也会庞大。但是换成工厂模式就不会。

参考设计模式之禅的工厂模式,女娲造人造黑种人,白种人,黄种人。(ps:原书作者写的很有意思,烤焦了变黑人,烤白了,经验不足,黄种人,正好完美,2333333)。用八卦炉去造人,下达的命令不是我要去造一个具体细节的人种(例如跑得飞快,头发颜色焦炭的黑人),而是直接说命令早黑种人,就会生成一个黑种人。
定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

通用工厂类图

工厂模式的优点:

  • 良好的封装性,代码结构清晰。一个对象的创建是有条件约束的,比如一个调用者需要一个小白车,只需要知道小白车的图纸的名称,不用知道小白车是如何将轮子,将油漆等等创建出来的,降低模块的耦合性。
  • 扩展性非常优秀,需要需要小黄车,只需要继承汽车产品,再去再添加一个小黄车的具体产品的实现方案就行了。
  • 屏蔽产品类。这一特点非常重要。比如android中下载一张图片,我不管你是用httpUrlConnection还是okhttp去实现。这些细节对我不重要,我只需要知道你能给我下载图片就行了。具体用哪个看情况就是了,而且切换无需修改实现代码。
  • 工厂模式是典型的解耦框架,高层模块只需要知道产品的抽象类,其他的实现类都不用关心,符合迪米特法则,我不需要就不用交流,也符合依赖倒置原则,只依赖产品类的抽象;当然符合里氏替换原则原则,使用产品子类替换父类。

工厂模式的扩展:

  1. 简单工厂模式
    一个模块只需要一个工厂类,直接去除抽象的工厂,并且不需要产生,直接静态的方法就可以实现了。

优点,比标准版调用简单。
缺点,工厂类的扩展就比较困难了。

  1. 多个工厂模式
    一个产品对应一个工厂类,每个工厂类就负责创建对应的产品对象,非常符合单一职责原则。

优点,创建类职责清晰,结构简单。
缺点,可扩展性和可维护性破坏了,每次扩展都需要创建一个产品类,就需要一个工厂类,增加扩展的复杂度。


扩展

  1. 替代单例模式
    通过工厂模式在内存中生产一个对象。通过反射获取当前不允许new 对象的类的对象,获取其中的方法。然后设置访问权限,但是要注意保存内存中的对象唯一,不能多次反射获取。
  2. 延迟初始化
    一个对象消费完毕后,并不立刻释放,工厂类保持初始状态,等待再此使用。用map缓存创建好的工厂,如果下次再调用,查询map中是否拥有,有就直接取出生产产品。

多用于限制一个产品类的最大实例化数量,或者对象初始化比较复杂的情况下,通过延迟加载降低对象的产生和销毁带来的复杂性。

参考书籍
设计模式之禅

单例模式

一般分为 饿汉式 懒汉式 线程不安全的 线程安全的 以及内部类形式的单例。

为什么使用单例?好处呢?

因为单例在内存中只有一个实例,减少内存的开销。主要一般适用于一个对象需要频繁的创建、销毁,而且无法优化创建和销毁时的性能。避免对资源的多重占用。可以全局调用。

缺点?

  • 单例模式一般没有接口,扩展很困难,基本都是修改代码实现。
  • 与单一指责原则冲突。
  • 对测试不利
  1. 饿汉式 一步到位 类初始化时,就实例化instance

    private static SingletonDesign instance = new SingletonDesign();

    private SingletonDesign(){

    }
    public static SingletonDesign getInstance(){
        return instance;
    }
  1. 懒汉式 (线程不安全的)为什么不安全,是因为如果多个线程同时创建单例,则会失效,可能创建多个instance。
private static SingletonDesign instance = null;

    private SingletonDesign(){

    }
    public static SingletonDesign getInstance(){
        if (instance == null){
            instance = new SingletonDesign();
        }
        return instance;
    }

3 懒汉式(线程安全的)但是因为加了synchronized 所以效率低。

private static SingletonDesign instance = null;

    private SingletonDesign(){

    }

    public synchronized static SingletonDesign getInstance(){
        if (instance == null){
            instance = new SingletonDesign();
        }
        return instance;
    }

4 静态内部类 比饿汉式效率稍微高点,因为这种开始并不一定会获取instance,而是去调用getInstance时候才去实例化instance

private static class Singletonholder{
        private static final SingletonDesign instance= new SingletonDesign();


    }
    private SingletonDesign(){

    }
    public static final SingletonDesign getInstance(){
        return Singletonholder.instance;
    }

5 双重锁单例 懒汉线程安全版的升级

private volatile static SingletonDesign instance = null;

    private SingletonDesign(){

    }

    public  static SingletonDesign getInstance(){
        if (instance == null){
            synchronized (SingletonDesign.class){
                if (instance == null){
                    instance = new SingletonDesign();
                }
            }

        }
        return instance;
    }

设计模式之禅

常见的几种单例模式