工厂模式(Factory Pattern)
工厂模式是 Java 中最常用的设计模式之一
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象
介绍
意图:由工厂类创建一系列实现同一接口的对象
主要解决:主要解决接口选择的问题
何时使用:我们明确地计划不同条件下创建不同实例时
应用实例:
1.日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方
2.数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时
优点:
1.一个调用者想创建一个对象,只要知道其名称就可以了
2.扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以
3.屏蔽产品的具体实现,调用者只关心产品的接口
缺点:
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖
实现
1.Shape:同一接口
2.Circle/Square/Rectangle:实现Shape接口的类对象
3.ShapeFactory:通过getShape() -> 创建三种Shape
抽象工厂模式(Abstract Factory Pattern)
抽象工厂模式是围绕一个超级工厂创建其他工厂,该超级工厂又称为其他工厂的工厂
介绍
意图:工厂模式只能创建单一系列实例,抽象工厂用于扩展多系列实例
主要解决:主要解决接口选择的问题
何时使用:有多个系列实例需要由工厂创建
应用实例:
网易云换肤要把主页评论等各个模块实例都替换掉
优点:针对多系列实例,无需copy多个工厂
缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的Creator 里加代码,又要在具体的里面加代码
实现
1.Shape/Color:同一接口
2.Circle/Square/Rectangle - Red/Green/Blue:实现同一接口的类对象
3.AbstractFactory:工厂的抽象父类
4.ShapeFactory/ColorFactory:继承AbstractFactory的工厂类对象,用于生产对象
5.FactoryProducer:用于生产AbstractFactory实体类
单例模式(Singleton Pattern)
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一
这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建
这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象
注意:
- 单例类只能有一个实例
- 单例类必须自己创建自己的唯一实例
-
介绍
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点
主要解决:一个全局使用的类频繁地创建与销毁
何时使用:当您想控制实例数目,节省系统资源的时候
如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建
应用实例: Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行
- 一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件
优点:
- 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)
- 避免对资源的多重占用(比如写文件操作)
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化
实现
我们将创建一个 SingleObject 类。SingleObject 类有它的私有构造函数和本身的一个静态实例。
SingleObject 类提供了一个静态方法,供外界获取它的静态实例。SingletonPatternDemo 类使用 SingleObject 类来获取 SingleObject 对象。
1.饿汉式
1.基础类
是否 Lazy 初始化:否
是否多线程安全:是
// 单例模式 - 核心私有构造方法[禁止额外初始化]
private Example01() {
}
// 饿汉式
private static final Example01 instance = new Example01();
public static Example01 getInstance() {
return instance;
}
2.枚举类
/**
* 单例模式 - 枚举[无构造方法,防止反序列化]
*
* @author gdq
* date 2021/3/15
*/
public enum Example04 {
// 单例变量
INSTANCE;
/**
* 获取实例
*
* @return Example04 实例对象
* @author gdq
* @since 2021/3/15
*/
public static Example04 getInstance() {
return INSTANCE;
}
}
2.懒汉式
是否 Lazy 初始化:是
是否多线程安全:是
1.doubleCheck / volatile 多线程二次确认
// 懒汉式 - doubleCheck / volatile屏蔽指令重排序
private static volatile Example02 INSTANCE = null;
public static Example02 getInstance() {
if (INSTANCE == null) {
synchronized (Example02.class) {
if (INSTANCE == null) {
INSTANCE = new Example02();
}
}
}
return INSTANCE;
}
2.静态内部类 - jvm初始化
// 静态内部类 - jvm控制类只有一次初始化
private static class Example03Holder {
private static final Example03 INSTANCE = new Example03();
}
/**
* 获取实例
*
* @return Example03 实例对象
* @author gdq
* @since 2021/3/15
*/
public static Example03 getInstance() {
return Example03Holder.INSTANCE;
}
建造者模式(Builder Pattern)
建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象
这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式
一个 Builder 类会一步一步构造最终的对象
介绍
意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
主要解决:主要解决在软件系统中,有时候面临着”一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定
何时使用:一些基本部件不会变,而其组合经常变化的时候
如何解决:拆分部件分别构造
应用实例: 1.lombok@builer 2.JAVA 中的 StringBuilder
优点:1.建造者独立,易扩展 2.便于控制细节风险
缺点:1.如内部变化复杂,会有很多的建造方法
实现
lombok.builder
package org.gdq.learn.design.build;
import lombok.ToString;
/**
* Example
*
* @author gdq
* @since 2021/8/12
*/
@ToString
public class Example {
// 组件1
private String item1;
// 组件2
private int item2;
// 组件3
private double item3;
// 组件4
private boolean item4;
public static ExampleBuilder builder() {
return new ExampleBuilder();
}
// 建造者
public static class ExampleBuilder {
// 组件1
private String item1;
// 组件2
private int item2;
// 组件3
private double item3;
// 组件4
private boolean item4;
/**
* 构造组件1
*
* @param item1 组件1
* @return ExampleBuilder 返回建造者
* @author gdq
* @since 2021/8/12
*/
public ExampleBuilder item1(String item1) {
this.item1 = item1;
return this;
}
/**
* 构造组件2
*
* @param item2 组件2
* @return ExampleBuilder 返回建造者
* @author gdq
* @since 2021/8/12
*/
public ExampleBuilder item2(int item2) {
this.item2 = item2;
return this;
}
/**
* 构造组件3
*
* @param item3 组件3
* @return ExampleBuilder 返回建造者
* @author gdq
* @since 2021/8/12
*/
public ExampleBuilder item3(double item3) {
this.item3 = item3;
return this;
}
/**
* 构造组件4
*
* @param item4 组件4
* @return ExampleBuilder 返回建造者
* @author gdq
* @since 2021/8/12
*/
public ExampleBuilder item4(boolean item4) {
this.item4 = item4;
return this;
}
public Example build() {
Example example = new Example();
example.item1 = this.item1;
example.item2 = this.item2;
example.item3 = this.item3;
example.item4 = this.item4;
return example;
}
}
}
原型模式(Prototype Pattern)
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆.当直接创建对象的代价比较大时,则采用这种模式.例如,一个对象需要在一个高代价的数据库操作之后被创建.我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用.
介绍
意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
主要解决:在运行期建立和删除原型
何时使用:1.当要实例化的类是在运行时刻指定时,例如,通过动态装载
如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例
关键代码: 1.实现克隆操作,在 JAVA 继承 Cloneable,重写 clone()
应用实例:1.JAVA 中的 Object clone() 方法
优点:1.性能提高 2.逃避构造函数的约束
缺点:1.配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候