Head First 设计模式笔记(第四章 工厂模式 & 第五章 单例模式)

第四章工厂模式 p109~147, 第五章单例模式 p148~189.

概述

工厂模式将类实例化集中化了. 代码变为Pizza pizza = PizaFactory.Create("SomePizzaType");
单例模式使得类保持一个实例.

工厂模式

多个类具有同样的行为, 类之间的实现又有一些差异. 求同存异, 这就需要我们抽象出来一些接口, 接口是共同的, 接口内的实现是有差异的.

共同的接口, 是让我们可以把这些类可以当作同一种类型进行处理, 增加了代码的统一性, 减少类似冗余代码的产生.

这时, 类的构建就成为一个问题, 一般来说, 将字符串和类映射起来, BaseClass instance = ClassFactory.Create("ClassType");, 觉得字符串不安全, 可以使用枚举.

本质上来说, 就是将一个If Else的类创建过程, 搬到了一个类中去实现.

对依赖的影响
使用者不应该依赖具体的类, 也就是使用者的代码中不应该出现SomeType instance = new SomeType();, 这样使用者就依赖这个具体的类. 如果这个类有变化, 如某个方法(非接口的方法)不再使用了, 或者调整参数了, 那么所有的使用者也要发生改变, 这样是不稳定的.

使用者应该依赖接口,BaseClass instance = ClassFactory.Create("ClassType");, 这样就是按接口使用, 接口一般来说是不会改变的. 同时, 对于接口的实现要求也比较高, 最好一开始就设计好, 不会改变.

接口对于扩展大有帮助, 有了接口后, 只要接口满足要求, 再新增一种类型就很轻松.

使用工厂模式前

使用工厂模式后

单例模式

维持一个独一无二的实例.

经典单例

public class Singleton1 {
    private static Singleton1 uniqueInstance;

    private Singleton1() {
    }

    public static Singleton1 getInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton1();
        }
        return uniqueInstance;
    }
}

线程不安全, 多线程下无法保持一个实例.

经典单例加锁

public class Singleton2 {
    private static Singleton2 uniqueInstance;

    private Singleton2() {
    }

    public static synchronized Singleton2 getInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton2();
        }
        return uniqueInstance;
    }
}

在方法上加了synchronized, 这是给方法加锁, 在每次调用该方法前需要检查锁, 一次只允许一个线程访问, 其它线程等待.
锁会降低这个方法的性能.

静态创建

public class Singleton3 {
    private static Singleton3 uniqueInstance = new Singleton3();

    private Singleton3() {
    }

    public static Singleton3 getInstance() {
        return uniqueInstance;
    }
}

在JVM初始化时进行创建, 能够保证单例的唯一性, 缺点是占用内存, 占用启动时间.

经典模式 + 单次锁

public class Singleton4 {
    private static Singleton4 uniqueInstance;

    private Singleton4() {
    }

    public static Singleton4 getInstance() {
        if (uniqueInstance == null) {
            synchronized (Singleton4.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new Singleton4();
                }
            }
        }
        return uniqueInstance;
    }
}

由于经典模式加锁影响性能, 其实只需要创建实例的那一次才需要加锁, 所以就有这种单次锁的情况. 在实例创建之后, 先进行一个If判断, 不会进入加锁的代码片段, If判断的开销远小于锁的开销. 所以性能大幅提升.

现实场景

工厂模式

这个是我日常用的最多的模式, 简单自然.

单例模式

用的少, 日常都是用静态方法或者属性才完成, 很少写单例.

猜你喜欢

转载自www.cnblogs.com/winwink/p/HeadFirstPattern_P3_Factory-Singleton.html