第四章工厂模式 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判断的开销远小于锁的开销. 所以性能大幅提升.
现实场景
工厂模式
这个是我日常用的最多的模式, 简单自然.
单例模式
用的少, 日常都是用静态方法或者属性才完成, 很少写单例.