个人博客:打开链接
建造者模式定义
建造者模式(Builder Pattern) 也叫做生成器模式,其定义如下:
Separate the construction of a complex object from its representation so that the same construction process can create different representations.
建造者模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
车模例子
例子:我们要生产一个简单车模(汽车模型),汽车模型要有启动、停止、引擎发出声音、喇叭响等功能。现在我要让用户根据自己的喜好来选择这些功能的顺序。
我们做出了下面的设计,其UML图为:
//汽车模型的抽象类
public abstract class CarModel{
//sequence就是客户要求执行的方法的顺序
private ArrayList<String> sequence = new ArrayList<String>();
protected abstract void start();
protected abstract void stop();
protected abstract void alarm();
protected abstract void engineBoom();
final public void run(){
for(int i = 0; i < this.sequence.size(); ++i){
String actionName = this.sequence.get(i);
if(actionName.equalsIgnoreCase("start")){
this.start();
}else if(actionName.equalsIgnoreCase("stop")){
this.stop();
}else if(actionName.equalsIgnoreCase("alarm")){
this.alarm();
}else if(actionName.equalsIgnoreCase("engine boom")){
this.engineBoom();
}
}
}
final public void setSequence(ArrayList<String> sequence){
this.sequence = sequence;
}
}
//Benz模型
public class BenzModel extends CarModel {
@Override
protected void start() {
System.out.println("奔驰车开始跑。。。");
}
@Override
protected void stop() {
System.out.println("奔驰车停下。。。");
}
@Override
protected void alarm() {
System.out.println("奔驰车喇叭响...");
}
@Override
protected void engineBoom() {
System.out.println("奔驰车的引擎发出声音了。。。");
}
}
//宝马模型
public class BMWModel extends CarModel {
@Override
protected void start() {
System.out.println("宝马车开始跑。。。");
}
@Override
protected void stop() {
System.out.println("宝马车停下。。。");
}
@Override
protected void alarm() {
System.out.println("宝马车喇叭响...");
}
@Override
protected void engineBoom() {
System.out.println("宝马车的引擎发出声音了。。。");
}
}
public class Client {
public static void main(String[] args) {
BenzModel benz = new BenzModel();
ArrayList<String> sequence = new ArrayList<String>();
sequence.add("engine boom");//客户要求,引擎先发出声音
sequence.add("start");//开始跑
sequence.add("stop");
benz.setSequence(sequence);
benz.run();
}
}
我们现在的设计能够满足客户的要求。可是如果有多个用户呢?可能你需要设计多个场景类来满足。难道你要一个一个的写场景类么?这会把你逼疯的… 我们为了每种模型产品模型定义一个创造者,你要啥顺序直接告诉创造者,由创造者来创建,于是乎我们就有了如下UML类图:
增加了一个CarBuilder抽象类,由它来组装各个车模,要什么类型什么顺序的车辆模型,都由相关的子类完成。
//我们新增的汽车建造者抽象类
public abstract class CarBuilder {
public abstract void setSequence(ArrayList<String> sequence);
public abstract CarModel getCarModel();
}
//奔驰建造者实现类
public class BenzBuilder extends CarBuilder {
private BenzModel benz = new BenzModel();
@Override
public CarModel getCarModel() {
return this.benz;
}
@Override
public void setSequence(ArrayList<String> sequence) {
this.benz.setSequence(sequence);
}
}
//宝马建造者实现类
public class BMWBuilder extends CarBuilder {
private BMWModel bmw;
@Override
public CarModel getCarModel() {
// TODO Auto-generated method stub
return this.bmw;
}
@Override
public void setSequence(ArrayList<String> sequence) {
this.bmw.setSequence(sequence);
}
}
//场景类
public class Client {
public static void main(String[] args) {
/*
*
*/
//存放run的顺序
ArrayList<String> sequence = new ArrayList<String>();
sequence.add("engine boom");//客户要求,run的时候先发动引擎
sequence.add("start");//启动起来
sequence.add("stop");//开了一段时间就停下来
//要一个奔驰车
BenzBuilder benzBuilder = new BenzBuilder();
//把顺序给这个builder类,制造出这样一个车出来
benzBuilder.setSequence(sequence);
//制造出一个奔驰车
BenzModel = benz = (BenzModel) benzBuilder.getCarModel();
//奔驰车跑一下看看
benz.run();
}
}
为了实现车模的四个过程执行顺序可任意,我们在引入一个Direct导演类,负责按照指定的顺序生成模型,其UML类如为:
//导演类
public class Director {
private ArrayList<String> sequence = new ArrayList<String>();
private BenzBuilder benzBuilder = new BenzBuilder();
private BMWBuilder bmwBuilder = new BMWBuilder();
/*
* A类型的奔驰车
*/
public BenzModel getABenzModel(){
this.sequence.clear();
this.sequence.add("start");
this.sequence.add("stop");
this.benzBuilder.setSequence(sequence);
return (BenzModel)this.benzBuilder.getCarModel();
}
/*
* B类型的奔驰车
*/
public BenzModel getBBenzModel(){
this.sequence.clear();
this.sequence.add("start");
this.sequence.add("alarm");
this.sequence.add("stop");
this.benzBuilder.setSequence(sequence);
return (BenzModel)this.benzBuilder.getCarModel();
}
//好多种...
}
//场景类
public class Client {
public static void main(String[] args) {
Director director = new Director();
for(int i = 0; i < 10; ++i){
director.getABenzModel().run();
}
for(int i = 0; i < 10; ++i){
director.getBBenzModel().run();
}
}
}
建造者模式的通用类图
Product产品类
通常是实现了模板方法模式,也就是有模板方法和基本方法。
Builder抽象建造者
规范产品的组建,一般是由子类实现。
ConcreteBuilder具体创建者
实现抽象类定义的所有方法,并且返回一个组建好的对象。
Director导演类
负责安排已有模块的顺序,然后告诉Builder开始创建。
//产品类
public class Product {
public void doSomething() {
//独立业务处理
}
}
//抽象创造者
public abstract class Builder {
//设置产品的不同部分,以获得不同的产品
public abstract void setPart();
//创建产品
public abstract Product buildProduct();
}
//具体创造者
public class ConcreteProduct extends Builder {
private Product product = new Product();
//设置产品零件
public void setPart() {
/*
*产品类内部的逻辑处理
*/
}
//组建一个产品
public Product buildProduct() {
return product;
}
}
//导演类
public class Director {
private Builder builder = new ConcreteProduct();
//构建不同的产品
public Product getAProduct() {
builder.setPart();
/*
*设置不同的零件,产生不同的产品
*/
return builder.builderProduct();
}
}
建造者模式的优点
- 封装性
- 建造者独立,容易拓展。BenzBuilder和BMWBuilder是相互独立的,对系统的拓展非常有利。
- 便于控制细节风险。因为具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生影响。
建造者模式的使用场景
- 相同的方法,不同的顺序,产生不同的事件结果时
- 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时
- 产品类非常复杂,或者产品类中的调用方法的顺序不同产生了不同的效能
建造者模式的注意事项
建造者模式关注的是零件类型和装配工艺(顺序),而工厂方法关心的整体的对象。二者虽然都是创建类设计模式,但还是有很大不同,不要用混了。
建造者模式最主要的功能是基本方法的调用顺序安排,也就是这些基本方法已经实现了,通俗地说就是零件的装配,顺序不同产生的对象也不同;而工厂方法模式则重点是创建,创建零件是它的主要职责,组装顺序则不是它关心的。