设计模式(5) ——- 建造者模式
- 一天天过的好快,玩了好几天该正式看点东西了~\~
- 下面介绍建造者模式,建造者模式与工厂模式有点类似。但是建造者模式更注重建造细节,而工厂模式注重的是结果。
- 一般建造者模式利用在复杂类里面。比如类中有繁琐的建造过程或者有多个参数。
- 这里首先,我们应该在学习时铭记设计模式的一般目的: 封装、可扩展等等,要不在有些时候会感觉可以使用更简单的代码代替而不理解为什么这么写。其实,自己认为的简单代码往往不满足上述要求。懂了这个后,就可以渐渐地理解它为什么这么做了。
概述
建造者模式
建造者模式能够将将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示
在建造者模式里,有个指导者,由指导者来管理建造者,用户是与指导者相互联系,指导者联系建造者最后得到产品。建造者模式可以强制实施一种分步骤进行的建造过程。
建造者模式是将复杂的内部创建封装在内部,对于外部调用的人来说看,只需要传入建造者和建造工具,关于内部是如何建成成品的,调用者无需关心。建造者模式的组成
Builder(抽象建造者)
两类方法。一类是 buildPartX() ,用来完成产品某部件的建造,一般调用产品类中的 set 方法。另一类是 getResult() ,用来返回复杂对象。
ConcreteBuilder(具体建造者)
Builder 的实现类或者是继承类。
Product(产品角色)
目标对象,最终的目的就是产生该类或者其子类的实例。
Director(指挥者)
它复杂调用建造者里面的方法安排复杂对象的建造次序。
说明:看到这有点迷糊没关系,看看下面的例子就明白了。
建造者模式的图示
举例说明
案例一
- 汽车部件问题
假如要通过一个汽车加工厂组装一辆汽车。其中汽车由车头、车身和车尾 3 部分组成。它的基本组装步骤如下:1,组装车头;2,组装车身;3,组装车尾。不管被组装的是吉普车,卡车,还是公交车,它们都可以各自重新定义车头、车身和车尾的组装方法。
代码
package 建造者模式.汽车部件案例; /** * 产品类 * @author by kissx on 2017/2/1. */ public class Car { private String head; private String body; private String tail; public void setBody(String body) { this.body = body; } public String getHead() { return head; } public void setHead(String head) { this.head = head; } public String getBody() { return body; } public String getTail() { return tail; } public void setTail(String tail) { this.tail = tail; } } package 建造者模式.汽车部件案例; /** * 创建产品的操作抽象 * @author by kissx on 2017/2/1. */ public interface Builder { void buildHead(); void buildBody(); void buildTail(); Car getCar(); } package 建造者模式.汽车部件案例; /** * 具体创建类 * @author by kissx on 2017/2/1. */ public class JeepBuilder implements Builder { private Car car = new Car(); @Override public void buildHead() { car.setHead("创建吉普的车头!"); } @Override public void buildBody() { car.setBody("创建吉普的车身!"); } @Override public void buildTail() { car.setTail("创建吉普的车尾!"); } @Override public Car getCar() { return car; } } package 建造者模式.汽车部件案例; /** * 具体实现类 * @author by kissx on 2017/2/1. */ public class MicroBusBuilder implements Builder { private Car car = new Car(); @Override public void buildHead() { car.setHead("创建面包车车头!"); } @Override public void buildBody() { car.setBody("创建面包车车身!"); } @Override public void buildTail() { car.setTail("创建面包车车尾!"); } @Override public Car getCar() { return car; } } package 建造者模式.汽车部件案例; /** * 建造者 * @author by kissx on 2017/2/1. */ public class CarDirector { private Builder builder; public CarDirector(Builder builder) { this.builder = builder; } public void construct(){ builder.buildHead(); builder.buildBody(); builder.buildTail(); } } package 建造者模式.汽车部件案例; /** * 用于测试 * @author by kissx on 2017/2/1. */ public class Client { public static void main(String[] args) { Builder jeepBuilder = new JeepBuilder(); CarDirector jeepDirector = new CarDirector(jeepBuilder); jeepDirector.construct(); Car jeep = jeepBuilder.getCar(); System.out.println("吉普: " + jeep.getBody()); Builder microBusBuilder = new MicroBusBuilder(); CarDirector microBusDirector = new CarDirector(microBusBuilder); microBusDirector.construct(); Car microBus = microBusBuilder.getCar(); System.out.println("面包车: " + microBus.getBody()); } }
说明:每个类的开头注释已经说明了每个类的作用,这里就不再具体分析了。这个案例是建造者模式最标准的形式。
- 汽车部件问题
案例二
- 三维模型问题
假设某位 3ds Max 牛人刚刚接收到了公司的任务,为某著名广告公司设计奔驰和宝马的模型,要求汽车的启动、停止、喇叭声音、引擎声音都由客户自己控制,司机想要什么顺序就实现什么顺序。这里要求实现奔驰、宝马两种产品。
代码
package 建造者模式.三维模型案例; import java.util.ArrayList; import java.util.List; /** * 产品抽象类 * @author by kissx on 2017/2/1. */ public abstract class CarModel { private List<String> actionList = new ArrayList<>(); public abstract void alarm(); public abstract void engineBoom(); public abstract void start(); public abstract void stop(); final public void run(){ for (String anActionList : actionList) { switch (anActionList) { case "start": System.out.println("启动!"); break; case "stop": System.out.println("熄火!"); break; case "alarm": System.out.println("鸣笛!"); break; default: System.out.println("引擎声!"); break; } } } final public void setActionList(List<String> actionList){ this.actionList = actionList; } } package 建造者模式.三维模型案例; /** * 具体实现类 * @author by kissx on 2017/2/1. */ public class BenzModel extends CarModel { @Override public void alarm() { System.out.println("奔驰的喇叭响!"); } @Override public void engineBoom() { System.out.println("奔驰的引擎声!"); } @Override public void start() { System.out.println("奔驰跑起来了!"); } @Override public void stop() { System.out.println("奔驰停车!"); } } package 建造者模式.三维模型案例; /** * 具体实现类 * @author by kissx on 2017/2/1. */ public class BMWModel extends CarModel { @Override public void alarm() { System.out.println("宝马的喇叭响!"); } @Override public void engineBoom() { System.out.println("宝马的引擎响!"); } @Override public void start() { System.out.println("宝马跑起来了!"); } @Override public void stop() { System.out.println("宝马停车!"); } } package 建造者模式.三维模型案例; import java.util.List; /** * 抽象创建类 * @author by kissx on 2017/2/1. */ public abstract class CarModelBuilder { public abstract void setActionList(List<String> actionList); public abstract CarModel getModel(); } package 建造者模式.三维模型案例; import java.util.List; /** * 具体创建类 * @author by kissx on 2017/2/1. */ public class BenzModelBuilder extends CarModelBuilder { BenzModel benzModel = new BenzModel(); @Override public void setActionList(List<String> actionList) { benzModel.setActionList(actionList); } @Override public CarModel getModel() { return benzModel; } } package 建造者模式.三维模型案例; import java.util.List; /** * 具体创建类 * @author by kissx on 2017/2/1. */ public class BMWModelBuilder extends CarModelBuilder{ BMWModel bmwModel = new BMWModel(); @Override public void setActionList(List<String> actionList) { bmwModel.setActionList(actionList); } @Override public CarModel getModel() { return bmwModel; } } package 建造者模式.三维模型案例; import java.util.ArrayList; import java.util.List; /** * 创建者 * @author by kissx on 2017/2/1. */ public class CarModelDirector { private List<String> actionList = new ArrayList<>(); private BMWModelBuilder bmwModelBuilder = new BMWModelBuilder(); private BenzModelBuilder benzModelBuilder = new BenzModelBuilder(); public BenzModel getABenzModel(){ //这里返回类型为 CarModel 即可,下面类似 actionList.clear(); actionList.add("start"); actionList.add("stop"); benzModelBuilder.setActionList(actionList); return (BenzModel) benzModelBuilder.getModel(); } public BenzModel getBBenzModel(){ actionList.clear(); actionList.add("engine boom"); actionList.add("start"); actionList.add("stop"); benzModelBuilder.setActionList(actionList); return (BenzModel) benzModelBuilder.getModel(); } public BMWModel getCBMWModel(){ actionList.clear(); actionList.add("alarm"); actionList.add("start"); actionList.add("stop"); bmwModelBuilder.setActionList(actionList); return (BMWModel) bmwModelBuilder.getModel(); } } package 建造者模式.三维模型案例; /** * 测试类 * @author by kissx on 2017/2/1. */ public class Client { public static void main(String[] args) { CarModelDirector director = new CarModelDirector(); CarModel benzModel = director.getABenzModel(); benzModel.run(); } }
说明:这个案例比较复杂。注意这里的产品类是 CarModel ,它是一个抽象类。你可能会感觉 Builder 类有点多余(我一开始是这麽想的~\~),其实这样写是为了封闭具体的实现类。别的不多说了,慢慢体会吧!
- 三维模型问题
案例三
- 特殊应用
不多说,直接上代码。
代码
package 建造者模式.特殊利用; /** * @author by kissx on 2017/2/1. */ public class Race { private String name; private String skinColor; private String sex; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSkinColor() { return skinColor; } public void setSkinColor(String skinColor) { this.skinColor = skinColor; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } } package 建造者模式.特殊利用; /** * @author by kissx on 2017/2/1. */ public class RaceBuilder { private Race race; public RaceBuilder builder(){ this.race = new Race(); return this; } public RaceBuilder setName(String name){ race.setName(name); return this; } public RaceBuilder setSex(String sex){ race.setSex(sex); return this; } public RaceBuilder setSkinColor(String skinColor){ race.setSkinColor(skinColor); return this; } public Race create(){ return this.race; } } package 建造者模式.特殊利用; /** * @author by kissx on 2017/2/1. */ public class Client { public static void main(String[] args) { Race race = new RaceBuilder().builder() .setName("张三") .setSex("男") .setSkinColor("黄") .create(); } }
说明:这里直接看 Client 测试类即可,是否感觉有点面熟,如果你写过 Android 应该是这样的。在创建一个类的时候若有多个参数且具体应用时有几个参数需要填写不确定这是可以使用上面方法,这样就很方便了。
- 特殊应用
总结
建造者模式与工厂模式的区别就是其比较注重建造过程。在写的时候牢牢记住它的组成就比较容易了。至于什么时候用,这里可以借鉴上面的三个例子,还需要以后自己慢慢总结喽!