[把你的理性思维慢慢变成条件反射]
本文,我们讲介绍建造者模式,文章主题结构与上文一致。惯例,先来看看我们示例工程的环境:
操作系统:win7 x64
其他软件:eclipse mars,jdk7
-------------------------------------------------------------------------------------------------------------------------------------
经典问题:
将某个过程进行抽象、一个复杂对象,流程的创建,执行过程,等“具体某个‘产品’的‘生产过程’”
思路分析:
要点一:对象需要经历多个步骤才能生成。
要点二:这个步骤,过程能够抽象,或者,过程处理具有相似性。
示例工程:
本文以建造一个机器人为例。
错误写法:
创建RobotABuilder.java,RobotBBuilder.java文件,具体内容如下:
package com.csdn.ingo.gof_builder;
public class RobotABuilder {
private String panel;
private String color;
public RobotABuilder(String panel, String color) {
this.panel = panel;
this.color = color;
}
public void build() {
System.out.println("panel:"+panel);
System.out.println("color:"+color);
System.out.println("step1:head");
System.out.println("step2:body");
System.out.println("step3:limb");
}
}
创建Window.java文件,具体内容如下:
package com.csdn.ingo.gof_builder;
public class Window {
public static void main(String[] args) {
RobotBBuilder t = new RobotBBuilder("white", "red");
t.build();
RobotABuilder f = new RobotABuilder("black", "blue");
f.build();
}
}
错误原因:
RobotA,RobotB具有相似的创建过程。但是,上面的创建代码完全没有做出应有的抽象整合,造成较多的冗余代码。
推荐写法:
创建RobotBuilder.java文件,具体内容如下:
package com.csdn.ingo.gof_builder.one;
public abstract class RobotBuilder {
protected String panel;
protected String color;
public RobotBuilder(String panel,String color){
this.panel = panel;
this.color = color;
}
public abstract void buildHead();
public abstract void buildBody();
public abstract void buildlimb();
}
创建RobotDirector.java文件,具体内容如下:
package com.csdn.ingo.gof_builder.one;
public class RobotDirector {
private RobotBuilder pb;
public RobotDirector(RobotBuilder pb) {
this.pb = pb;
}
public void createPerson(){
pb.buildHead();
pb.buildBody();
pb.buildlimb();
}
}
创建RobotABuilder.java,RobotBBuilder.java文件,具体内容如下:
package com.csdn.ingo.gof_builder.one;
public class RobotABuilder extends RobotBuilder {
public RobotABuilder(String panel, String color) {
super(panel, color);
}
@Override
public void buildHead() {
// TODO Auto-generated method stub
System.out.println("A step1:head");
}
@Override
public void buildBody() {
// TODO Auto-generated method stub
System.out.println("A step2:body");
}
@Override
public void buildlimb() {
// TODO Auto-generated method stub
System.out.println("A step3:limb");
}
}
创建Window.java文件,具体内容如下:
package com.csdn.ingo.gof_builder.one;
public class Window {
public static void main(String[] args) {
RobotBBuilder p = new RobotBBuilder("white", "red");
RobotDirector pd = new RobotDirector(p);
pd.createPerson();
RobotABuilder pf = new RobotABuilder("black", "blue");
RobotDirector pdf = new RobotDirector(pf);
pdf.createPerson();
}
}
推荐原因:
这种写法区分出了,对象创建过程中的可变过程与不变过程。使客户端明确的感受到对象创建过程中必须传入的内容,必须实现的过程。更加有利于模型改变的表达。
模式总结:
标准建造者模式UML结构图:
概念总结:
建造者模式:讲一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
组成部分:Director(指挥者,具体的步骤设计)。Builder(建造者抽象接口类)。ConcreteBuilder(具体步骤实现类)。Product.java(具体产品)四部分组成。
模板代码:
创建Builder.java文件,具体内容如下:
package com.csdn.ingo.gof_builder.two;
public abstract class Builder {
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
public abstract Product getResult();
}
创建ConcreteBuilder1.java,ConcreteBuilder2.java文件,具体内容如下:
package com.csdn.ingo.gof_builder.two;
public class ConcreteBuilder1 extends Builder{
private Product p = new Product();
@Override
public void buildPartA() {
// TODO Auto-generated method stub
p.add("part-A");
}
@Override
public void buildPartB() {
// TODO Auto-generated method stub
p.add("part-B");
}
@Override
public void buildPartC() {
// TODO Auto-generated method stub
p.add("part-C");
}
@Override
public Product getResult() {
// TODO Auto-generated method stub
return p;
}
}
创建Director.java文件,具体内容如下:
package com.csdn.ingo.gof_builder.two;
public class Director {
public void Construct(Builder builder){
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
}
}
创建Product.java文件,具体内容如下:
package com.csdn.ingo.gof_builder.two;
import java.util.ArrayList;
import java.util.List;
public class Product {
List<String> parts = new ArrayList<String>();
public void add(String part) {
parts.add(part);
}
public void show() {
System.out.println("---list---");
for(String part:parts){
System.out.println(part);
}
}
}
特别的:一般情况下Product为Java对象时,多为值对象等,如下:
public class Product {
private String partA; //定义部件,部件可以是任意类型,包括值类型和引用类型
private String partB;
private String partC;
//partA的Getter方法和Setter方法省略
//partB的Getter方法和Setter方法省略
//partC的Getter方法和Setter方法省略
}
另外,可以将Director中的Construst方法增加返回值,方便客户端使用。
模板功能扩展:
- 将Director与Builder进行合并。(Builder为抽象类,可将construst方法变为静态方法,放入到Builder中)
- 如果在客户端没有传入参数的条件下,可以在第一条的基础上,将construst方法的参数直接移除,改为直接调用Builder本身的方法即可。
- 为了精确的控制到某一个具体的创建方法时候执行,可以引入我们在前文中介绍的钩子方法。(即,在Builder抽象类中增加一个布尔型的钩子方法,并赋予默认值,然后在其子类当中,重写该方法,并在相应的具体方法上增加钩子方法的判断,即可实现方法界别的精确控制。)
反思:
应用场景:
- 需要创建的对象拥有复杂的内部结构,通常情况下其包含有多个成员变量。
- 对象属性间存在依赖关系,即可能需要执行生成顺序。
- 创建过程可以从对象所属的类当中独立出来。即Product的创建过程抽象在Director中。
- 隔离复杂对象的创建和使用,并且使得相同的过程可以创建不同的产品。
优点:
- 细节依赖于抽象。向客户端屏蔽整个对象的创建过程,并且创建过程本身依赖抽象,保证对象创建过程一致性。
- 具体的建造者可以存在多个,并且每一个具体的建造者相互之间保持独立性。增加系统的维护性,扩展性。
- 对每一步骤的细节可以更加精确的把控。
- 在引入配置文件,反射机制之后,可以动态的,在运行时改变整个建造策略,及相应的结果。
缺点:
- 必须要求产品之间存在相同的创建过程。
- 必须要求产品具有创建过程上的稳定性,一旦建造过程发生变化,必须修改对应的Director。
- 对于数量较多的相似对象,可能存在较多的具体产品类。应当做好抽象工作,防止系统内部出现过多的子类。
-------------------------------------------------------------------------------------------------------------------------------------
至此,被说了很多遍的设计模式---建造者模式 结束
参考资料:
图书:《大话设计模式》
其他博文:http://blog.csdn.NET/lovelion/article/details/7563445