欢迎各位大神指教!
参考文献:HTTPS://LOVE2.IO/@WEBETA/DOC/DESIGN-PATTERN-JAVA
根据某个模式用于处理类之间的关系还是处理对象之间的关系,设计模式可分为类模式和对象模式。
一、简单工厂模式 Simple Factory Pattern
类型:类创建型模式。
本不属于23种工厂模式之中,但使用频率较多,固作为学些其他工厂模式的入门。
定义:定义一个工厂类,根据参数的不同返回不同类的实例,被创建的实例通常都是拥有共同的父类。
换言之:需要什么,就给工厂角色传入相应的参数,即可获取到所需的对象。不需要知道具体创建细节。
角色:
Factory 工厂角色;(核心)
Product 抽象产品角色;
ConcreteProduct 具体产品角色;
注:创建实例的方法是静态方法(static)。
优点:
- 实现了对象创建和使用的分类。
- 只需知道所需对象的相应参数,而无须记住相应类名。
缺点:
- 用于创建对象的工厂类过于庞大,工厂类包含了所有对象创建逻辑,耦合度太高,职责过大,一旦无法出现问题,整个系统都会被影响。
- 使用简单工厂模式会增加系统中类的个数,增大系统的复杂度和理解难度。
- 扩展难度大。如需添加新产品,必须修改工厂类,违背“开闭原则”;
- 工厂方法使用了静态方法,导致了无法形成继承的等级结构。
使用场景:
- 工厂创建的对象数较少;
- 只知道所需对象的相应参数,不关心创建细节。
二、工厂方法模式 Factory Method Pattern
类型:类创建型模式。
定义:定义一个用于创建工厂的接口,让子类决定用哪个类来实例化。
换言之:具体工厂继承工厂接口,具体子类实现工厂方法,创建具体对象。
工厂方法模式又称为,工厂模式、多态工厂模式。
角色:
- Factory 抽象工厂
- ConcreteFactory 具体工厂
- Product 抽象产品
- ConcreteProduct 具体产品
优点:
- 添加新产品无须修改抽象工厂和抽象产品,符合“开闭原则”;
- 使用了基于抽象工厂和产品工厂的多态性设计。
- 创建对象时,只需关心具体产品工厂,无须关系具体产品类名及创建细节。
缺点:
- 添加新的工厂和产品,系统中类数将增加,增加了系统复杂度。
- 考虑到可扩展性,引入了抽象层,增加了系统抽象性和理解难度。
使用场景:
- 不知道所需对象所属的类。
三、抽象工厂模式 Abstract Factory Pattern
类型:对象创建型模式。
定义:定义一个创建一系列相关或相互依赖对象的接口。无须指定具体的类。
换言之:在抽象工厂中,定义一个产品族,而非产品等级结构。
产品等级结构与产品族
-
产品等级结构:产品的继承结构;例如:抽象类是电视机,子类是海尔电视机、海信电视机、TCL电视机。抽象电视机和具体电视机是一个产品等级结构。
-
产品族:在抽象工厂模式中,产品族指的是由同一个工厂生产的,位于不同产品等级结构中的一组产品。如海尔电器工厂生产的海尔洗衣机、海尔电视、海尔冰箱,海尔洗衣机位于洗衣机产品等级结构中,海尔电视机位于电视机产品等级结构中,海尔冰箱位于冰箱产品等级结构中。海尔洗衣机、海尔电视机、海尔冰箱构成了一个产品族。
开闭原则的倾斜性:在抽象工厂模式中,增加新的产品族很方便,增加新的产品等级结构很麻烦。
角色:
- AbstractFactory 抽象工厂
- ConcreteFactory 具体工厂
- AbstractProduct 抽象产品
- ConcreteProduct 具体产品
优点:
- 添加产品族很方便。
- 因为一个产品族中包含多个对象,在使用时可以保证客户端始终使用的是同一个产品族中的对象。
- 更换一个具体工厂很方便。
缺点:
- 添加新的产品等级结构很麻烦原则。违背了“开闭”;
使用场景:
- 产品等级结构稳定。
- 有多个产品族,只使用某一个产品族的情况。
JAVA中的AWT,使用了抽象工厂模式。
四、单例模式 Singleton Pattern
类型:对象创建型模式。
定义:确保一个类只有一个实例,而且自行实例化,并向整个系统提供这个实例。
角色:
- Singleton 单例
两种实现方式:
- 饿汉式单例(立即加载):在定义静态变量的时候,实例化单例类。在类加载时,自行实例化。
- 懒汉式单例(延迟加载 lazy load):在第一次调用实例化方法时进行实例化,在类加载时并不自行实例化。即需要的时候,再加载实例。为避免多个线程同时调用实例化方法,可对实例化方法使用synchronized关键字,进行线程锁。
双重检查锁定:
引用:在某一瞬间线程A和线程B都在调用getInstance()方法,此时instance对象为null值,
均能通过instance == null的判断。由于实现了synchronized加锁机制,线程A进入synchronized锁定的
代码中执行实例创建代码,线程B处于排队等待状态,必须等待线程A执行完毕后才可以进入synchronized锁
定代码。但当A执行完毕时,线程B并不知道实例已经创建,将继续创建新的实例,导致产生多个单例对象,违背
单例模式的设计思想,因此需要进行进一步改进,在synchronized中再进行一次(instance == null)判断,
这种方式称为双重检查锁定(Double-Check Locking)。
class LazySingleton {
private volatile static LazySingleton instance = null;
private LazySingleton() { }
public static LazySingleton getInstance() {
//第一重判断
if (instance == null) {
//锁定代码块
synchronized (LazySingleton.class) {
//第二重判断
if (instance == null) {
instance = new LazySingleton(); //创建单例实例
}
}
}
return instance;
}
}
注:如果使用双重检查锁定来实现懒汉式单例类,需要在静态成员变量instance之前增加修饰符volatile,被volatile修饰的成员变量可以确保多个线程都能够正确处理,且该代码只能在JDK 1.5及以上版本中才能正确执行。由于volatile关键字会屏蔽Java虚拟机所做的一些代码优化,可能会导致系统运行效率降低,因此即使使用双重检查锁定来实现单例模式也不是一种完美的实现方式。
饿汉式与懒汉式比较
饿汉式
优点:无须考虑多线程访问问题,保证实例唯一性;因类加载时就创建实例,调用和反应时间要快于懒汉式。
缺点:对系统资源利用率要比懒汉式低。加载时间可能会比较长。
懒汉式
优点:实现了延迟加载,无须一直占用资源。
缺点:对了多线程同时访问,需要进行线程锁处理。
优点:
- 提供了唯一实例进行访问;
- 节约了系统资源。
缺点:
- 由于没有抽象层,扩展困难。
- 长时间不适用,会被回收并释放资源。导致共享的单例对象状态的丢失。
使用场景:
- 只需要一个实例对象。
五、原型模式 Prototype Pattern
类型:对象创建型模式。
定义:确保一个类只有一个实例,而且自行实例化,并向整个系统提供这个实例。
角色:
- Prototype 抽象原型类
- ConcretePrototype 具体原型类
- Client 客户类
浅克隆与深克隆区别:
是否支持引用类型的成员变量的复制。
优点:
- 使用深刻用可以保存对象状态。
- 创建对象复杂情况下,可通过克隆简化对象创建过程。
缺点:
- 每个类都需覆盖克隆方法。
- 深克隆实现代码复杂。
六、建造者模式 Builder Pattern
类型:对象创建型模式。
定义:将复杂对象的创建和表示分离。
角色:
- Builder 抽象建造者
- ConcreteBuilder 具体建造者
- Product 产品角色
- Director 指挥者
钩子方法:
判断某个方法是否被调用,返回类型一般为布尔类型。
优点:
- 将产品的创建和产品本身分离,实现松耦合。
- 具体建造者相对独立,方便添加新的建造者。
缺点:
- 该模式创建的产品一般为有较多共同点。