创建型模式

创建型模式 Creational Patterns

  • 创建型模式关注如何创建对象,将对象的实例化和声明相分离。
  • 关注于对象的创建过程,目的是将对象的实例化与客户端的使用分离。
  • 通过这种方式,系统中的具体类的实例化不会使代码变得僵硬,增加了系统的灵活性和可维护性。
  • 更有效地封装和抽象化对象的创建过程。

创建型模式包括:

  • 单例模式(Singleton):确保一个类只有一个实例,并提供一个全局访问点。
  • 工厂方法模式(Factory Method):定义一个创建对象的接口,让子类决定实例化哪一个类。
  • 抽象工厂模式(Abstract Factory):提供一个接口,用于创建相关或依赖对象的家族,而不需要指定具体类。
  • 建造者模式(Builder):使用多个简单的对象一步一步构建成一个复杂的对象。
  • 原型模式(Prototype):通过复制现有的实例来创建新的实例,而不是通过新建实例。

单例模式

保证一个类只有一个实例, 并提供一个访问该实例的全局节点。

懒汉式双重校验锁(DCL,即 double-checked locking)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton {  
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
  • volatile: 这是 Java 语言的一个关键字,用于指示 JVM(Java 虚拟机),这个变量可能会被多个线程同时访问和修改,但是它不会被线程缓存(每次访问变量时都要从主内存中读取),并且每次修改都会立即写入主内存。这个关键字的主要作用是确保变量的可见性和防止指令重排序优化,这对于多线程环境下安全创建单例至关重要。

工厂方法模式

  • 在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。
  • 如果无法预知对象确切类别及其依赖关系时, 可使用工厂方法。
  • 如果你希望用户能扩展你软件库或框架的内部组件, 可使用工厂方法。
  • 如果你希望复用现有对象来节省系统资源, 而不是每次都重新创建对象, 可使用工厂方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public interface Shape {
void draw();
}
////////////////////////////////
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println();
}
}
//////////////
public class ShapeFactory {

//使用 getShape 方法获取形状类型的对象
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if ...
return null;
}
}

抽象工厂模式

  • 创建一系列相关的对象
  • 无需指定其具体类。
  • 其他工厂的工厂。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//定义抽象工厂

public interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}

// 接着,定义 Button 和 Checkbox 接口:

public interface Button {
void paint();
}

public interface Checkbox {
void paint();
}

// 然后,实现具体的工厂类 WinFactory 和 MacFactory:

public class WinFactory implements GUIFactory {
@Override
public Button createButton() {
return new WinButton();
}

@Override
public Checkbox createCheckbox() {
return new WinCheckbox();
}
}

public class MacFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacButton();
}

@Override
public Checkbox createCheckbox() {
return new MacCheckbox();
}
}

// 定义具体产品类 WinButton, WinCheckbox, MacButton, 和 MacCheckbox:

public class WinButton implements Button {
@Override
public void paint() {
System.out.println("Rendering a button in Windows style.");
}
}

public class MacButton implements Button {
@Override
public void paint() {
System.out.println("Rendering a button in macOS style.");
}
}

public class WinCheckbox implements Checkbox {
@Override
public void paint() {
System.out.println("Rendering a checkbox in Windows style.");
}
}

public class MacCheckbox implements Checkbox {
@Override
public void paint() {
System.out.println("Rendering a checkbox in macOS style.");
}
}

// 最后,实现客户端代码 Application 和 ApplicationConfigurator:

public class Application {
private GUIFactory factory;
private Button button;

public Application(GUIFactory factory) {
this.factory = factory;
}

public void createUI() {
this.button = factory.createButton();
}

public void paint() {
button.paint();
}
}

public class ApplicationConfigurator {
public static void main(String[] args) {
GUIFactory factory;
String OS = System.getProperty("os.name");

if (OS.contains("Windows")) {
factory = new WinFactory();
} else if (OS.contains("Mac")) {
factory = new MacFactory();
} else {
throw new RuntimeException("Error! Unknown operating system.");
}

Application app = new Application(factory);
app.createUI();
app.paint();
}
}

这段 Java 代码完整实现了抽象工厂模式,包括抽象工厂接口、具体工厂类、抽象产品接口、具体产品类以及客户端代码。客户端代码仅依赖于抽象类型(GUIFactory、Button 和 Checkbox),使得你可以在不修改客户端代码的情况下引入新的工厂或产品变体。

建造者模式

  • AKA生成器模式
  • 分步骤创建复杂对象
  • 使用相同的创建代码生成不同类型和形式的对象。
  • 链式编程
  • 只有当产品较为复杂且需要详细配置时,使用生成器模式才有意义。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
public class Car {
// 假设这里有一些属性和方法来表示汽车的各种特性
}

public class Manual {
// 假设这里有一些属性和方法来表示手册的各种特性
}

// 接下来是 `Builder` 接口的定义,包括创建产品对象不同部件的方法:

public interface Builder {
void reset();
void setSeats(int number);
void setEngine(String engine);
void setTripComputer(boolean present);
void setGPS(boolean present);
}

// 然后,我们实现具体的生成器类 `CarBuilder` 和 `CarManualBuilder`:

public class CarBuilder implements Builder {
private Car car;

public CarBuilder() {
this.reset();
}

@Override
public void reset() {
this.car = new Car();
}

@Override
public void setSeats(int number) {
// 实现设置座位数的逻辑
}

@Override
public void setEngine(String engine) {
// 实现设置引擎的逻辑
}

@Override
public void setTripComputer(boolean present) {
// 实现设置行车电脑的逻辑
}

@Override
public void setGPS(boolean present) {
// 实现设置GPS的逻辑
}

public Car getProduct() {
Car product = this.car;
this.reset();
return product;
}
}

public class CarManualBuilder implements Builder {
private Manual manual;

public CarManualBuilder() {
this.reset();
}

@Override
public void reset() {
this.manual = new Manual();
}

@Override
public void setSeats(int number) {
// 实现添加关于座椅的文档逻辑
}

@Override
public void setEngine(String engine) {
// 实现添加关于引擎的介绍逻辑
}

@Override
public void setTripComputer(boolean present) {
// 实现添加关于行车电脑的介绍逻辑
}

@Override
public void setGPS(boolean present) {
// 实现添加关于GPS的介绍逻辑
}

public Manual getProduct() {
Manual product = this.manual;
this.reset();
return product;
}
}

// 接着,实现 `Director` 类,它负责定义构建过程的不同步骤:

public class Director {
public void constructSportsCar(Builder builder) {
builder.reset();
builder.setSeats(2);
builder.setEngine("SportEngine");
builder.setTripComputer(true);
builder.setGPS(true);
}

// 这里可以添加更多的方法来构建不同类型的汽车
}

// 最后是客户端代码,它演示了如何使用这些类来构建产品:

public class Application {
public static void main(String[] args) {
Director director = new Director();

CarBuilder carBuilder = new CarBuilder();
director.constructSportsCar(carBuilder);
Car car = carBuilder.getProduct();

CarManualBuilder manualBuilder = new CarManualBuilder();
director.constructSportsCar(manualBuilder);
Manual manual = manualBuilder.getProduct();

// 在这里,car 和 manual 是根据相同的构建过程创建的,
// 但它们是完全不同的产品。
}
}

这段 Java 代码展示了如何实现生成器模式,其中包括创建复杂对象的过程,使得最终产品的构建与其表示分离,允许相同的构建过程创建不同的表示。

原型模式

  • 复制已有对象

  • 当直接创建对象的代价比较大时,则采用这种模式。

  • Java 中,原型模式通常通过实现 Cloneable 接口并重写 Object 类的 clone() 方法来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import java.util.HashMap;
import java.util.Map;

// 抽象类实现 Cloneable 接口
abstract class Shape implements Cloneable {
private String id;
protected String type;

abstract void draw();

public String getType() {
return type;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}

// 具体的形状类
class Rectangle extends Shape {
public Rectangle() {
type = "Rectangle";
}

@Override
void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}

class Circle extends Shape {
public Circle() {
type = "Circle";
}

@Override
void draw() {
System.out.println("Inside Circle::draw() method.");
}
}

// 缓存类
class ShapeCache {
private static Map<String, Shape> shapeMap = new HashMap<>();

public static Shape getShape(String shapeId) {
Shape cachedShape = shapeMap.get(shapeId);
return (Shape) cachedShape.clone();
}

public static void loadCache() {
Circle circle = new Circle();
circle.setId("1");
shapeMap.put(circle.getId(), circle);

Rectangle rectangle = new Rectangle();
rectangle.setId("2");
shapeMap.put(rectangle.getId(), rectangle);
}
}

// 客户端代码
public class PrototypePatternDemo {
public static void main(String[] args) {
ShapeCache.loadCache();

Shape clonedShape1 = ShapeCache.getShape("1");
System.out.println("Shape : " + clonedShape1.getType());

Shape clonedShape2 = ShapeCache.getShape("2");
System.out.println("Shape : " + clonedShape2.getType());
}
}

这段代码展示了原型设计模式的核心:通过克隆现有对象来创建新对象,从而避免了通过 new 关键字创建对象带来的成本。这里,Shape 抽象类实现了 Cloneable 接口,允许其子类 RectangleCircle 被克隆。ShapeCache 类用于预存储和克隆形状对象,而客户端代码演示了如何从缓存中获取并使用这些克隆对象。

end