建造者模式 & 原型模式

[Musings]
最近沉迷设计模式了,挺好玩的,今天是建造者模式,最常见的builder,通过链式调用来方便构造,这个是我日常使用中觉得最实用的

建造者模式

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
//Order.class
public class Order {
private String mainFood;
private int number;
private String address;

Order(String address) {
this.address = address;
}

public void setMainFood(String mainFood) {
this.mainFood = mainFood;
}

public void setAddress(String address) {
this.address = address;
}

public void setNumber(int number) {
this.number = number;
}
}
//OrderBuilder.interface
public interface OrderBuilder {
OrderBuilder setMainFood(String mainFood);

OrderBuilder setNumber(int number);

Order build();
}
//MeituanOrderBuilder.class
public class MeituanOrderBuilder implements OrderBuilder {
private Order order;

public MeituanOrderBuilder(String address) {
this.order = new Order(address);
}

@Override
public OrderBuilder setMainFood(String mainFood) {
this.order.setMainFood(mainFood);
return this;
}

@Override
public OrderBuilder setNumber(int number) {
this.order.setNumber(number);
return this;
}

@Override
public Order build() {
return this.order;
}
}
//Main.class
public class Main {
public static void main(String[] args) {
MeituanOrderBuilder builder = new MeituanOrderBuilder("123");
Order abc = builder.setMainFood("abc")
.setNumber(12)
.build();
}
}

这是第一个简单版本的,然后我就想,如果在调用的时候可以写成下面这个版本,就更舒服了

1
2
3
4
5
6
7
8
9
public class Main {
public static void main(String[] args) {
// MeituanOrderBuilder builder = new MeituanOrderBuilder("123");
Order abc = Order.withMeituanBuilder()
.setMainFood("abc")
.setNumber(12)
.build();
}
}

然后我就开始班门弄斧,其实就是抽象工厂+建造者模式,builder返回不同的抽象工厂,然后每个工厂去做建造

1
2
3
4
5
6
7
8
package org.example.builder;

public class Order {
// {...}
public static MeituanOrderBuilder withMeiTuanBuilder(String address){
return new MeituanOrderBuilder(address);
}
}

主要这里考虑的几个点:

  1. 建造者通过对超多参数的情况进行优化,防止构造函数过于复杂
  2. 通过链式调用来清晰明了的书写代码
  3. 考虑是否使用final来修饰字段,这样可以确保建造者模式在set完以后是固定的

第三点其实根据场景和设计需求考虑,设计模式本身就是灵活的,一起都要基于业务场景的上下文来实现,而不是单纯的照抄,理解核心原理,就像打太极一样,学会了,又好像没学,什么都忘了,想用的时候,让灵感飘动起来

所以到此为止,记住特性的区别
🏭 工厂方法:一个产品,多种实现
🏭 抽象工厂:一套产品,整体替换
🔨 建造者:复杂对象,分步构建
📋 原型:已有对象,复制使用
👑 单例:全局唯一,严格控制

原型模式

原型模式的核心就是两个

  1. 实现cloneable接口,重写clone方法
  2. 注意深浅拷贝,对于引用对象实现深拷贝
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
//Address.java
public class Address implements Cloneable{
private String city;
private List<String> tags = new ArrayList<>();

public List<String> getTags() {
return tags;
}

public void setTags(List<String> tags) {
this.tags = tags;
}

public String getCity() {
return city;
}

public void setCity(String city) {
this.city = city;
}

//拷贝构造函数
public Address(Address other){
this.city = other.city;
this.tags = new ArrayList<>(other.tags);
}

//手动实现拷贝构造函数
@Override
protected Object clone() throws CloneNotSupportedException {
Address clone = (Address) super.clone();
clone.tags = new ArrayList<>(this.tags);
return clone;
}
}

//Main.class
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address();
Address clone = (Address) address.clone();
address.getTags().add("1");
System.out.println(address); //tag :[1]
System.out.println(clone); // tag: []
}
}

其实很简单,就这么个逻辑