建造者模式听起来有点高大上, 也是程序猿之间常常提起的模式之一.
其实它有1个前提跟模板方法模式(Template Method)有点类似, 就是建造这个过程可以分拆成若干个部分(步骤).
我们先看定义.
一, 建造者模式的定义
建造者模式(Builder), 将1个复杂对象的构建与它的表示分离. 使得同样的构建过程可以创建不同的表示.
定义很简练啊.
关键词如下:
什么是 构建?
什么是 表示?
什么是 分离?
这里先简单解释一下:
构建:
就是完成1件由若干步骤组成的过程.
表示:
就是将对象表达出来(文字表达, 图形表达..等)
分离:
就是代码写在不同的类中.
下面举几个例子详解.
二, 使用模板方法模式 实现 汽车制造的1个简单例子.
我们假设, suppose, 1辆汽车的制造过程只有3步:
1. 制造引擎.
2. 制造车身.
3. 制造论坛
现在要求做1个可以实现 制造Fort汽车 和 Benz汽车 的类设计.
我们以前讲过, 模板方法可以实现步骤分离.
那么先试着使用模板方法实现:
2.1 抽象类MakeCar
public abstract class MakeCar {
private ArrayList<String> partList = new ArrayList<String>();
ArrayList<String> getPartList(){
return this.partList;
}
abstract void buildEngine();
abstract void buildBody();
abstract void buildwheels();
public void build(){
this.buildEngine();
this.buildBody();
this.buildwheels();
}
public void show(){
System.out.println(this.getClass().getSimpleName() + ": " + this.getPartList());
}
}
注意,
里面的 build() 相当于构建(由若干步骤组成)
里面的 show() 就相当于表示了.
2.2 类MakeFortCar
public class MakeFortCar extends MakeCar{
@Override
void buildEngine() {
// TODO Auto-generated method stub
this.getPartList().add("Fort-Engine");
}
@Override
void buildBody() {
// TODO Auto-generated method stub
this.getPartList().add("Fort-Body");
}
@Override
void buildwheels() {
// TODO Auto-generated method stub
this.getPartList().add("Fort-wheels");
}
}
2.3 类MakeFortCar
public class MakeBenzCar extends MakeCar{
@Override
void buildEngine() {
// TODO Auto-generated method stub
this.getPartList().add("Benz-Engine");
}
@Override
void buildBody() {
// TODO Auto-generated method stub
this.getPartList().add("Benz-Body");
}
@Override
void buildwheels() {
// TODO Auto-generated method stub
this.getPartList().add("Benz-wheels");
}
}
2.4 客户端代码:
MakeCar mFort = new MakeFortCar();
mFort.build();
mFort.show();
MakeCar mBenz = new MakeBenzCar();
mBenz.build();
mBenz.show();
这种写法的优点:
1.在客户端隐藏了构造过程的细节, 这个也是模板方法模式的优点.
2. 可以有多个子类继承同1个模板, 也就是同样可以实现一样可以实现 1个构建过程可以创建不同的表示.
然后看看这样的写法有什么缺点:
1. 看起来是汽车自己制造了自己, 没有1个建设者的角色存在. 无角色区别.
2. 构建方法build() 跟表示方法 show()写在同1个类. 没有分离
3. 若现实中构建方法build() , 也就是建造顺序一但修改, 若遵循封闭-开放 原则,则整套代码不适用了.
因为模板方法之所以叫做模板方法, 是因为模板本身是不改的, 一套类对应1个模板.
而, 汽车生产中, 建造顺序往往会有变化, 甚至有额外的工序. 例如货车需要1个集装箱等.
三, 使用建造者模式实现上面的例子.
建设者模式的角色有3个.
1. 产品(product) 就是指建造的产品, 这个例子指的就是汽车. 它有方法可以表示自己.
2. 建设者(Builder) 整个模式的核心, 它负责怎样去实现产品中每个部分(零件)的制造.
3. 指挥者(Director) 相当于1个项目经理模式, 它指挥产品中每个部分的完成顺序.
从解释中大概已经估算出, 构建方法在指挥者里, 表示方法在产品里.
具体代码如下:
3.1 产品类CarProduct:
import java.util.ArrayList;
public class CarProduct {
private ArrayList<String> partList = new ArrayList<String>();
private String brandName;
void addPart(String part){
this.partList.add(part);
}
void setbrand(String name){
this.brandName = name;
}
public void show(){
System.out.println(this.brandName + ":" + partList);
}
}
注意这里数组添加的部分是String格式, 实际项目中很可能是1个对象(零件类对象)
3.2 抽象建设者类CarBuilder
public abstract class CarBuilder {
private CarProduct prod = new CarProduct();
CarProduct getProd() {
return prod;
}
void setProd(CarProduct prod) {
this.prod = prod;
}
abstract void setBrand();
abstract void buildEngine();
abstract void buildBody();
abstract void buildWheels();
}
3.3 FortCarBuilder
public class FortCarBuilder extends CarBuilder {
@Override
void setBrand() {
// TODO Auto-generated method stub
this.getProd().setbrand("Fort");
}
@Override
void buildEngine() {
// TODO Auto-generated method stub
this.getProd().addPart("Fort-Engine");
}
@Override
void buildBody() {
// TODO Auto-generated method stub
this.getProd().addPart("Fort-Body");
}
@Override
void buildWheels() {
// TODO Auto-generated method stub
this.getProd().addPart("Fort-Wheels");
}
}
3.4 BenzCarBuilder
public class BenzCarBuilder extends CarBuilder {
@Override
void setBrand() {
// TODO Auto-generated method stub
this.getProd().setbrand("Benz");
}
@Override
void buildEngine() {
// TODO Auto-generated method stub
this.getProd().addPart("Benz-Engine");
}
@Override
void buildBody() {
// TODO Auto-generated method stub
this.getProd().addPart("Benz-Body");
}
@Override
void buildWheels() {
// TODO Auto-generated method stub
this.getProd().addPart("Benz-Wheels");
}
}
3.5 指挥者CarDirector()
public class CarDirector {
public void construct(CarBuilder cb){
cb.setBrand();
cb.buildEngine();
cb.buildBody();
cb.buildWheels();
}
}
3.6 客户端代码:
CarProduct prod;
CarDirector cd = new CarDirector();
CarBuilder cb = new FortCarBuilder();
cd.construct(cb);
prod = cb.getProd();
prod.show();
cb = new BenzCarBuilder();
cd.construct(cb);
prod = cb.getProd();
prod.show();
3. 7 UML
3. 8 这样用建造者模式实现的好处
1. 从客户端代码, 出现了指挥者, 建造者, 产品3种角色, 就如指挥者指挥建造者建造了产品一样. 跟业务逻辑结合得好
当然, 这个例子1个建造者(builder)只生产1个产品.
2. 构建过程卸载指挥者类里, 表示方法写在产品类里, 也就是构建过程与表示分离.
3. 同1个指挥者实现了两种产品(Fort Benz)的生产和表示, 也就是定义中的1个构建过程可以实现不同的表示.
4. 当某个产品的制造顺序改变是, 只需要新增1个指挥者子类, 让新的指挥者去指挥建设者生产就可以了. 其他类不受影响.
也就是说这种改动符合封闭 - 开放原则.