23种设计模式6_建造者模式
1 基本介绍
建造者模式也叫生成器模式,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式的UML类图:
如上图,建造者模式种有4种角色:
Product产品类 通常是实现了模板方法模式,也就是有模板方法和基本方法。
Builder抽象建造者 规范产品的组件,一般是由子类实现。
ConcreteBuilder具体建造者 实现抽象类定义的所有方法,并且返回一个组建好的对象。
Director导演类 负责安排已有模块的顺序,然后告诉Builder开始建造
2 建造者模式的通用代码
// 产品类
public class Product {
public void method() { /*业务逻辑处理*/ }
}
// 抽象建造者
public abstract class Builder {
// 这个方法用来设置生产不同的产品
public abstract void setDiff();
// 建造产品
public abstract Product buildProduct();
}
// 具体建造者
public class ConcreteBuilder extends Builder {
private Product product = new Product();
@Override
public void setDiff() { /*特定产品的处理逻辑*/ }
@Override
public Product buildProduct() {
return product;
}
}
// 导演类
public class Director {
private Builder builder = new ConcreteBuilder();
// 构造不同的产品
public Product getProduct() {
// 通过不同的处理逻辑产生不同的产品
builder.setDiff();
return builder.buildProduct();
}
}
3 案例演示
3.1 需求
生产汽车,有奔驰和奥迪两个品牌,两个品牌各有两种模型A和B,通用功能:启动、发出喇叭声、发出引擎声、熄火、行驶。客户需要自己定义各个品牌车模型所具有的功能。
3.2 代码演示
// 车辆模型的通用抽象类
public abstract class CarModel {
// 记录客户自定义的通用功能顺序
private ArrayList<String> sequence = new ArrayList<>();
// 启动
protected abstract void start();
// 喇叭声
protected abstract void alarm();
// 引擎声
protected abstract void engineBoom();
// 熄火
protected abstract void stop();
public final void run() {
for (String fucName : sequence) {
if ("启动".equals(fucName)) { this.start(); }
if ("喇叭声".equals(fucName)) { this.alarm(); }
if ("引擎声".equals(fucName)) { this.engineBoom(); }
if ("熄火".equals(fucName)) { this.stop(); }
}
}
public void setSequence(ArrayList<String> sequence) {
this.sequence = sequence;
}
}
// 奔驰模型
public class BenzModel extends CarModel {
@Override
protected void start() { System.out.println("奔驰车。。。。启动"); }
@Override
protected void alarm() { System.out.println("奔驰车。。。。喇叭声"); }
@Override
protected void engineBoom() { System.out.println("奔驰车。。。。引擎声"); }
@Override
protected void stop() { System.out.println("奔驰车。。。。熄火"); }
}
// 奥迪模型
public class AudiModel extends CarModel {
@Override
protected void start() { System.out.println("奥迪车。。。。..启动"); }
@Override
protected void alarm() { System.out.println("奥迪车。。。。..喇叭声"); }
@Override
protected void engineBoom() { System.out.println("奥迪车。。。。..引擎声"); }
@Override
protected void stop() { System.out.println("奥迪车。。。。..熄火"); }
}
// 抽象的建造者
public abstract class CarBuilder {
// 设置功能顺序
public abstract void setSequence(ArrayList<String> sequence);
// 设置完顺序后就可以获得车辆模型
public abstract CarModel getModel();
}
// 奔驰建造者
public class BenzBuilder extends CarBuilder{
private BenzModel benz = new BenzModel();
@Override
public void setSequence(ArrayList<String> sequence) {
this.benz.setSequence(sequence);
}
@Override
public CarModel getModel() {
return this.benz;
}
}
// 奥迪建造者
public class AudiBuilder extends CarBuilder{
private AudiModel audi = new AudiModel();
@Override
public void setSequence(ArrayList<String> sequence) {
this.audi.setSequence(sequence);
}
@Override
public CarModel getModel() {
return this.audi;
}
}
// 导演类
public class Director {
private ArrayList<String> sequence = new ArrayList<>();
private BenzBuilder benzBuilder = new BenzBuilder();
private AudiBuilder audiBuilder = new AudiBuilder();
private String start = "启动";
private String alarm = "喇叭声";
private String engineBoom = "引擎声";
private String stop = "熄火";
/* 客户车辆功能需求交给导演类进行管理整合
* 奔驰A:启动、喇叭声、引擎声、熄火
* 奔驰B:启动、引擎声、熄火
* 奥迪A:启动、熄火
* 奥迪B:喇叭声、启动、熄火
*/
// 奔驰A
public BenzModel getBenzAModel() {
// 全局属性需要清空,要么就定义到方法内部
this.sequence.clear();
sequence.add(start);
sequence.add(alarm);
sequence.add(engineBoom);
sequence.add(stop);
this.benzBuilder.setSequence(sequence);
return (BenzModel) this.benzBuilder.getModel();
}
// 奔驰B
public BenzModel getBenzBModel() {
this.sequence.clear();
sequence.add(start);
sequence.add(engineBoom);
sequence.add(stop);
this.benzBuilder.setSequence(sequence);
return (BenzModel) this.benzBuilder.getModel();
}
// 奥迪A
public AudiModel getAudiAModel() {
this.sequence.clear();
sequence.add(start);
sequence.add(stop);
this.audiBuilder.setSequence(sequence);
return (AudiModel) this.audiBuilder.getModel();
}
// 奥迪B
public AudiModel getAudiBModel() {
this.sequence.clear();
sequence.add(alarm);
sequence.add(start);
sequence.add(stop);
this.audiBuilder.setSequence(sequence);
return (AudiModel) this.audiBuilder.getModel();
}
}
public class Client {
public static void main(String[] args) {
Director director = new Director();
// 1w辆奔驰A
for (int i=0; i<30000; ++i) {
director.getBenzAModel().run();
}
System.out.println("==========================");
// 2w辆奔驰B
for (int i=0; i<30000; ++i) {
director.getBenzBModel().run();
}
System.out.println("==========================");
// 3w辆奥迪A
for (int i=0; i<30000; ++i) {
director.getAudiAModel().run();
}
System.out.println("==========================");
// 4w辆奥迪B
for (int i=0; i<40000; ++i) {
director.getAudiBModel().run();
}
}
}
4 建造者模式的应用
4.1 优点
①***封装性*** 使用建造者模式可以使客户端不必知道产品内部组成的细节
②建造者独立,容易扩展 相互独立,易于扩展
③便于控制细节风险 由于具体的建造者都是独立的,因此可以对建造过程逐步细化,而不会对其他的模块产生任何影响
4.2 应用场景
①相同的方法,不同的执行顺序,产生不同的事件结果时,可以采用建造者模式。
②多个部件或者零件都可以装配到一个对象种,但是产生的运行结果又不相同时,则可以使用该模式。
③产品类非常复杂,或者产品类种的调用顺序不同产生了不同的效用,这个时候建造者模式就非常合适。
④在对象的创建过程种会使用到系统中的一些其他对象,这些对象在产品对象的创建过程种不易得到时,也可以采用建造者模式来封装该对象的创建过程。这种场景只能是一个补偿方法,因为一个对象不容易获得,而在设计阶段竟没有发觉,而要通过建造者模式来柔化创建过程,本身就已经违反的设计的初衷。
4.3 注意事项
的执行顺序,产生不同的事件结果时,可以采用建造者模式。
②多个部件或者零件都可以装配到一个对象种,但是产生的运行结果又不相同时,则可以使用该模式。
③产品类非常复杂,或者产品类种的调用顺序不同产生了不同的效用,这个时候建造者模式就非常合适。
④在对象的创建过程种会使用到系统中的一些其他对象,这些对象在产品对象的创建过程种不易得到时,也可以采用建造者模式来封装该对象的创建过程。这种场景只能是一个补偿方法,因为一个对象不容易获得,而在设计阶段竟没有发觉,而要通过建造者模式来柔化创建过程,本身就已经违反的设计的初衷。
4.3 注意事项
建造者模式关注的是零件类型和装配工艺(顺序),这是它与工厂方法模式最大的不同,虽然同为创建类模式,但是侧重点不同。