-- 什么是建造者模式?
-- 建造者模式应用场景?
-- 建造者模式和工厂模式的区别?
定义
指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示。
应用场景
建造者(Builder)模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用。
- 创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。
- 创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。
实现
展现的是《设计模式之禅》里面的例子。以车模型为例,每种车都可根据几个动作排布。
CarModel.java
public abstract class CarModel { private ArrayList<String> sequence = new ArrayList<>(); 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 sequence) { this.sequence = sequence; } }
BenzModel.java
public class BenzModel extends CarModel { @Override protected void alarm() { System.out.println("奔驰车的喇叭声音是这个样子的..."); } @Override protected void engineBoom() { System.out.println("奔驰车的引擎是这个声音的..."); } @Override protected void start() { System.out.println("奔驰车跑起来是这个样子的..."); } @Override protected void stop() { System.out.println("奔驰车应该这样停车..."); } }
BMWModel.java
public class BMWModel extends CarModel { @Override protected void alarm() { System.out.println("宝马车的喇叭声音是这个样子的..."); } @Override protected void engineBoom() { System.out.println("宝马车的引擎是这个声音的..."); } @Override protected void start() { System.out.println("宝马车跑起来是这个样子的..."); } @Override protected void stop() { System.out.println("宝马车应该这样停车..."); } }
Client.java
public class Client { public static void main(String[] args) { //传统做法 BenzModel benz = new BenzModel(); ArrayList<String> sequence = new ArrayList<>(); sequence.add("engine boom"); // 客户要求,run的时候先发动引擎 sequence.add("start"); // 启动起来 sequence.add("stop"); // 开了一段就停下来 // 我们把这个顺序赋予奔驰车 benz.setSequence(sequence); benz.run(); } }
传统的做法到这里就直接将动作顺序在调用端一一列出来了,但这样的话,如果再来一个别的动作顺序,又得再列一大串代码,直到把你逼疯。其次,如果其他地方也要用到这个车模型,就得再copy一遍。下面加入建造者看下~
CarBuilder.java
public abstract class CarBuilder { public abstract void setSequence(ArrayList<String> sequence); public abstract CarModel getCarModel(); }
BenzBuilder.java
public class BenzBuilder extends CarBuilder { private BenzModel benz = new BenzModel(); @Override public void setSequence(ArrayList<String> sequence) { this.benz.setSequence(sequence); } @Override public CarModel getCarModel() { return benz; } }
BMWBuilder.java
public class BMWBuilder extends CarBuilder { private BMWModel bmw = new BMWModel(); @Override public void setSequence(ArrayList<String> sequence) { this.bmw.setSequence(sequence); } @Override public CarModel getCarModel() { return bmw; } }
建造者创建完了,还需要一个指挥官来指挥建造者才行,指挥官想生成3种类型的奔驰。
Director.java
public class Director { private ArrayList<String> sequence = new ArrayList<>(); 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("engine boom"); this.sequence.add("start"); this.sequence.add("stop"); this.benzBuilder.setSequence(sequence); return (BenzModel) this.benzBuilder.getCarModel(); } //C类型的奔驰 public BenzModel getCBenzModel() { //清理场景,这里是一些初级程序员不注意的地方 this.sequence.clear(); this.sequence.add("alarm"); this.sequence.add("start"); this.sequence.add("stop"); this.benzBuilder.setSequence(sequence); return (BenzModel) this.benzBuilder.getCarModel(); } }
Client.java
public class Client { public static void main(String[] args) { //传统做法 ... //建造者模式 System.out.println("==========A=========="); Director director = new Director(); director.getABenzModel().run(); System.out.println("==========B=========="); director.getBBenzModel().run(); System.out.println("==========C=========="); director.getCBenzModel().run(); } }
最后,在客户想要那种车模型的时候,指挥官就马上去安排了。
建造者模式和工厂模式的区别?
学完这个模式的时候,一开始还是有点蒙圈的,将初始化的零散工作放在一个方法里,在调用的时候直接根据类型去获取,这不是工厂模式吗?但仔细回想上个例子,汽车是一个工厂,然后子部件如空调,发动机作为一个单独的对象,在工厂里面有创建方法,当需要哪个部件的时候,就通过工厂方法去实例化出来。 而建造者模式是将A,B,C类型的车作为一个整体,通过指挥官去组装。
从这两个例子也就可以看出: 建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程。
《设计模式之禅》 对于这两者的区别是这么理解的:
建造者模式最主要的功能是基本方法的调用顺序安排,也就是这些基本方法已经实现了,通俗地说就是零件的装配,顺序不同产生 的对象也不同;
而工厂方法则重点是创建,创建零件是它的主要职责,组装顺序则不是它关心的。