概论
什么是建造者模式呢?将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式示例
我们先来回忆一下在模板模式中的 示例,[内外部系统交互]中的四个步骤:
第一步:参数校验
第二步:封装对外的请求参数
第三步:对外提交请求
第四步:后置处理,例如记录操作日志
最后核心的算法设计在run方法中。如下代码所示:
1 public voidrun (ExampleContext context) {2
3 validate(context);4
5 prepare(context);6
7 proccess(context);8
9 after(context);10 }
客户端只要取调用run方法就可以。一切看来都很美好,但是如果我们想要把第一步和第二步交换执行顺序。或者把第二步舍弃。或者第三步和第四步交换执行顺序等等。
简单的描述一下问题:我们想要在一个算法中若干个步骤,客户端需要自定义步骤的顺序以及确定是否采用或者舍弃一些步骤。
此时需要用到建造者模式。首先我们需要有抽象产品类:
1 public abstract classAbstractProccessor {2
3 private List sequence = new ArrayList();4
5
6
7 public booleanvalidate(ExampleContext context) {8 if (context == null) {9 return false;10 }11
12 return true;13 }14
15 public abstract voidprepare(ExampleContext context);16
17 public abstract voidproccess(ExampleContext context);18
19 public abstract voidafter(ExampleContext context);20
21 protected booleanneedAfterProccessing () {22 return true;23 }24
25
26 public ListgetSequence() {27 returnsequence;28 }29
30 public void setSequence(Listsequence) {31 this.sequence =sequence;32 }33
34 public voidrun (ExampleContext context) {35
36 for(String methodName : sequence) {37 if(StringUtils.isEmpty(methodName)) {38 continue;39 }40
41 Method method = null;42
43 try{44 method = this.getClass().getMethod(methodName, ExampleContext.class);45 } catch(Exception e) {46
47 }48
49 if(method == null) {50 continue;51 }52
53 try{54 method.invoke(this, context);55 } catch(Exception e) {56
57 }58
59
60 }61 }62
63 }
第3行:声明一个表示顺序的集合,集合中存储的是算法中每个步骤的方法名。类型为String类型。
第31行-61行:run方法通过遍历顺序集合的方式依次执行。通过反射的方式来调用。
接下来,和模板方法中的两个具体产品类完全一样,一个是HttpProccessor,另外一个是OtherProccessor。代码如下所示:
1 public class HttpProccessor extendsAbstractProccessor {2
3 protected boolean needAfterProccessing = false;4
5 @Override6 public voidprepare(ExampleContext context) {7
8 System.out.println("http 前置处理");9
10 }11
12 @Override13 public voidproccess(ExampleContext context) {14
15 System.out.println("http 提交请求");16
17 }18
19 @Override20 public voidafter(ExampleContext context) {21
22 System.out.println("http 后置处理");23
24 }25
26 }
1 public class OtherProccessor extendsAbstractProccessor {2
3 @Override4 public voidprepare(ExampleContext context) {5
6 System.out.println("other 前置处理");7
8 }9
10 @Override11 public voidproccess(ExampleContext context) {12
13 System.out.println("other 提交请求");14
15 }16
17 @Override18 public voidafter(ExampleContext context) {19
20 System.out.println("other 后置处理");21
22 }23 }
最后我们需要修改一下我们的场景类Client:
1 public classClient {2
3 public static voidmain(String[] args) {4
5 AbstractProccessor proccessor = newHttpProccessor();6
7 List list = new ArrayList();8 list.add("prepare");9 list.add("proccess");10 proccessor.setSequence(list);11
12 proccessor.run(newExampleContext());13
14
15 }16 }
第7行-10行:设置要执行的步骤以及顺序。
运行结果如下所示:
http 前置处理
http 提交请求
当我们需要很多种场景,是不是需要去写很多种负责的场景类?在建造者设计模式中引入一个很重要的角色--建造者。场景类需要什么顺序,只需要告诉建造者就行。
我们新增一个建造者抽象类AbtractorBuilder。
1 public abstract classAbstractBuilder {2
3 public abstract void setSequence(Listlist);4
5 public abstractAbstractProccessor getProccessor();6 }
再新增一个HttpBuilder和OtherBuilder
public class HttpBuilder extendsAbstractBuilder {private AbstractProccessor proccessor = newHttpProccessor();
@Overridepublic void setSequence(Listlist) {
proccessor.setSequence(list);
}
@OverridepublicAbstractProccessor getProccessor() {returnproccessor;
}
}
public class OtherBuilder extendsAbstractBuilder {private AbstractProccessor proccessor = newOtherProccessor();
@Overridepublic void setSequence(Listlist) {
proccessor.setSequence(list);
}
@OverridepublicAbstractProccessor getProccessor() {returnproccessor;
}
}
继续修改一下场景类:
1 public classClient {2
3 public static voidmain(String[] args) {4
5 List list = new ArrayList();6 list.add("prepare");7 list.add("proccess");8
9 HttpBuilder httpBuilder = newHttpBuilder();10 httpBuilder.setSequence(list);11
12 AbstractProccessor proccessor =httpBuilder.getProccessor();13 proccessor.run(newExampleContext());14
15 }16 }
但是我们的HttpBuilder还是在场景类中调用时,顺序还是不够灵活。 这时需要产生一个导演类,将所有预知的情况 组合的情况一一列出来。如下代码所示:
1 public classDirector {2
3 private List sequence = new ArrayList();4 private AbstractBuilder httpBuilder = newHttpBuilder();5 private AbstractBuilder otherBuilder = newOtherBuilder();6
7 publicAbstractProccessor getHttpProccessorFirst() {8
9 this.sequence.clear();10 sequence.add("prepare");11
12 httpBuilder.setSequence(sequence);13
14 AbstractProccessor proccessor =httpBuilder.getProccessor();15
16 returnproccessor;17 }18
19 publicAbstractProccessor getHttpProccessorSecond() {20
21 this.sequence.clear();22 sequence.add("prepare");23 sequence.add("after");24
25 httpBuilder.setSequence(sequence);26
27 AbstractProccessor proccessor =httpBuilder.getProccessor();28
29 returnproccessor;30 }31
32 publicAbstractProccessor getOtherProccessorFirst() {33
34 this.sequence.clear();35 sequence.add("prepare");36
37 otherBuilder.setSequence(sequence);38
39 AbstractProccessor proccessor =otherBuilder.getProccessor();40
41 returnproccessor;42 }43
44 publicAbstractProccessor getOtherProccessorSecond() {45
46 this.sequence.clear();47 sequence.add("prepare");48 sequence.add("after");49
50 otherBuilder.setSequence(sequence);51
52 AbstractProccessor proccessor =otherBuilder.getProccessor();53
54 returnproccessor;55 }56 }
最后我们在修改一下场景类:
1 public classClient {2
3 public static voidmain(String[] args) {4
5 AbstractProccessor proccessor = null;6
7 Director director = newDirector();8 proccessor =director.getHttpProccessorFirst();9 proccessor.run(newExampleContext());10
11 proccessor =director.getHttpProccessorSecond();12 proccessor.run(newExampleContext());13
14
15 proccessor =director.getOtherProccessorFirst();16 proccessor.run(newExampleContext());17
18 proccessor =director.getOtherProccessorSecond();19 proccessor.run(newExampleContext());20
21
22
23 }24 }
简单而明了,笔者在开发的过程中,遇到很多的开发者不注意代码质量,甚至连资深的技术专家都没有意识到这一点。写下一行代码需要10秒钟,而看懂一行代码确实需要很大的力气。因此设计模式是用简单的方式将复杂的业务需求清晰的表达出来。
最后总结一下。建造者模式是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
在建造者模式中有4个角色,分别是产品类,抽象建造者,具体建造者,导演。
建造者模式的优点
1.良好的封装:场景类不必知道产品内部的细节。
2.建造者的独立,良好的扩展:存在不同的具体建造者,每个建造者之间独立。
3.良好的控制风险:因为具体的建造者是相互独立的,因此建造过程也是独立的,不会某一个建造者的变动对其他造成影响。