设计模式-建造者模式

如果一个类中有很多属性,为了避免构造函数的参数列表过长,影响代码的可读性和易用性,我们可以通过构造函数配合 set() 方法来解决。但是,如果存在下面情况中的任意一种,我们就要考虑使用建造者模式了。

  • 我们把类的必填属性放到构造函数中,强制创建对象的时候就设置。如果必填的属性有很多,把这些必填属性都放到构造函数中设置,那构造函数就又会出现参数列表很长的问题。如果我们把必填属性通过 set() 方法设置,那校验这些必填属性是否已经填写的逻辑就无处安放了。
  • 如果类的属性之间有一定的依赖关系或者约束条件,我们继续使用构造函数配合 set() 方法的设计思路,那这些依赖关系或约束条件的校验逻辑就无处安放了。
  • 如果我们希望创建不可变对象,也就是说,对象在创建好之后,就不能再修改内部的属性值,要实现这个功能,我们就不能在类中暴露 set() 方法。构造函数配合 set() 方法来设置属性值的方式就不适用了。

工厂模式是用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象。建造者模式是用来创建一种类型的复杂对象,可以通过设置不同的可选参数,“定制化”地创建不同的对象。

ConstructorArg使用创建者模式重构

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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
public class BeanDefinition {

private String id;
private String className;
private List<ConstructorArg> constructorArgs = new ArrayList<>();
private Scope scope = Scope.SINGLETON;
private boolean lazyInit = false;

public String getId() {
return id;
}

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

public String getClassName() {
return className;
}

public void setClassName(String className) {
this.className = className;
}

public List<ConstructorArg> getConstructorArgs() {
return constructorArgs;
}

public void setConstructorArgs(List<ConstructorArg> constructorArgs) {
this.constructorArgs = constructorArgs;
}

public Scope getScope() {
return scope;
}

public void setScope(Scope scope) {
this.scope = scope;
}

public boolean isLazyInit() {
return lazyInit;
}

public void setLazyInit(boolean lazyInit) {
this.lazyInit = lazyInit;
}

public boolean isSingleton() {
return this.getScope().equals(Scope.SINGLETON);
}

public static enum Scope {
SINGLETON,
PROTOTYPE
}

public static class ConstructorArg {
private boolean isRef = false;
private Class type;
private Object arg;

public boolean isRef() {
return isRef;
}

public Class getType() {
return type;
}

public Object getArg() {
return arg;
}

private ConstructorArg(boolean isRef, Class type, Object arg) {
this.isRef = isRef;
this.type = type;
this.arg = arg;
}

public static class Builder{
private boolean ref = false;
private Class type;
private Object arg;

public ConstructorArg build() {
if (ref && type != null) {
throw new RuntimeException("bean为ref类型时type不需要设置");
}
if (!ref && (type == null || arg == null)) {
throw new RuntimeException("bean不为ref类型时type和arg必须填写");
}
return new ConstructorArg(ref, type, arg);
}

public Builder setRef(boolean ref) {
this.ref = ref;
return this;
}

public Builder setType(Class type) {
this.type = type;
return this;
}

public Builder setArg(Object arg) {
this.arg = arg;
return this;
}
}

}
}
// parse方法也需要更改
public List<BeanDefinition> parse(InputStream inputStream) {
List<BeanDefinition> beanDefinitions = new ArrayList<>();
try {
Document document = reader.read(inputStream);// 获取根节点
Element beans = document.getRootElement();
// 获取迭代器
Iterator beanIt = beans.elementIterator();
// 遍历迭代器,获取根节点信息
while(beanIt.hasNext()){
BeanDefinition beanDefinition = new BeanDefinition();
Element bean = (Element) beanIt.next();

List<Attribute> attributes = bean.attributes();
// 获取bean属性名和属性值
for (Attribute attribute : attributes) {
if ("id".equals(attribute.getName())) {
beanDefinition.setId(attribute.getValue());
} else if ("class".equals(attribute.getName())) {
beanDefinition.setClassName(attribute.getValue());
}
}
Iterator argsIt = bean.elementIterator();
List<BeanDefinition.ConstructorArg> constructorArgs = new ArrayList<>();
while(argsIt.hasNext()){
BeanDefinition.ConstructorArg.Builder builder = new BeanDefinition.ConstructorArg.Builder();
Element arg = (Element) argsIt.next();
List<Attribute> argAttributes = arg.attributes();
// 获取bean属性名和属性值
for (Attribute attribute : argAttributes) {
if ("type".equals(attribute.getName())) {
try {
builder.setType(Class.forName(attribute.getValue()));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
builder.setArg(arg.getText());
} else if ("ref".equals(attribute.getName())) {
builder.setRef(true);
builder.setArg(attribute.getValue());
}
}
constructorArgs.add(builder.build());
beanDefinition.setConstructorArgs(constructorArgs);
}
beanDefinitions.add(beanDefinition);
}
} catch (DocumentException e) {
throw new RuntimeException(e);
}
return beanDefinitions;
}