建造者模式定义
将一个复杂对象的构建与它的表示分离,使得同样的构造过程可以创建不同的表示。
建造者模式中的角色
- 产品类:通常是实现了模板方法模式,也就是有模板方法和基本方法。一个具体的产品对象。
- 具体建造者:实现抽象定义的所有方法,并且返回一个组建好的对象。
- 抽象建造者:规范产品的组建,一般是由子类实现。
- 导演类:负责安排已有模板的顺序,然后告诉抽象建造者开始创建。
实现简单建造者模式
网上有一个小故事非常好,拿过来借鉴下。说在KFC里面一般都有好几种可供客户选择的套餐,它可以根据客户所点的套餐,然后在后面做这些套餐,返回给客户的事一个完整的套餐。套餐主要包含汉堡、薯条、可乐、咖啡、派等组成部分,使用不同的组成部分就可以构建出不同的套餐。我们先来看看KFC的抽象类
public abstract class FoodModel { private ArrayListsequence = new ArrayList (); public void setSequence(ArrayList sequence){ this.sequence = sequence; } public abstract void drink();//喝 public abstract void packageA();//套餐A public abstract void fries();//薯条 public abstract void send();//派 public void order(){ for (int i = 0; i < this.sequence.size(); i++) { String str = this.sequence.get(i); if (str.equals("drink")){ this.drink(); }else if (str.equals("packageA")){ this.packageA(); }else if (str.equals("fries")){ this.fries(); }else if (str.equals("send")){ this.send(); } } }}
代码清单:套餐A代码
public class FoodA extends FoodModel { @Override public void drink() { System.out.println("可乐"); } @Override public void packageA() { System.out.println("鳕鱼汉堡套餐"); } @Override public void fries() { System.out.println("薯条(小)"); } @Override public void send() { System.out.println("菠萝派"); }}
代码清单:套餐B代码
public class FoodB extends FoodModel{ @Override public void drink() { System.out.println("咖啡"); } @Override public void packageA() { System.out.println("麦辣鸡腿堡套餐"); } @Override public void fries() { System.out.println("薯条(大)"); } @Override public void send() { System.out.println("香芋派"); }}
我们增加了一个场景类来进行测试
public class Test { public static void main(String[] args) { ArrayListsequence = new ArrayList (); sequence.add("drink"); sequence.add("send"); sequence.add("packageA"); sequence.add("fries"); FoodA foodA = new FoodA(); foodA.setSequence(sequence); foodA.order(); System.out.println("-------------------"); FoodB foodB = new FoodB(); foodB.setSequence(sequence); foodB.order(); }}
运行结果如下所示:
可乐菠萝派鳕鱼汉堡套餐薯条(小)-------------------咖啡香芋派麦辣鸡腿堡套餐薯条(大)
增加了一个FoodBuilder抽象类,由它来组合各种套餐,要什么套餐点餐顺序都由相关子类完成,首先编写FoodBuilder代码
public abstract class FoodBuilder { public abstract void setSequence(ArrayListsequence); public abstract FoodModel getFoodModel();}
代码清单:套餐A的组合类
public class FoodABuilder extends FoodBuilder { private FoodA foodA = new FoodA(); public void setSequence(ArrayListsequence){ this.foodA.setSequence(sequence); } public FoodModel getFoodModel(){ return foodA; }}
代码清单:套餐B的组合类
public class FoodBBuilder extends FoodBuilder{ private FoodB foodB = new FoodB(); public void setSequence(ArrayListsequence) { this.foodB.setSequence(sequence); } public FoodModel getFoodModel() { return foodB; }}
修改后的场景类
public class Test { public static void main(String[] args) { ArrayListsequence = new ArrayList (); sequence.add("drink"); sequence.add("send"); sequence.add("packageA"); sequence.add("fries"); FoodABuilder foodABuilder = new FoodABuilder(); foodABuilder.setSequence(sequence); FoodModel foodA = foodABuilder.getFoodModel(); foodA.order(); System.out.println("-------------------"); FoodBBuilder foodBBuilder = new FoodBBuilder(); foodBBuilder.setSequence(sequence); FoodModel foodB = foodBBuilder.getFoodModel(); foodB.order(); }}
运行结果如下所示
可乐菠萝派鳕鱼汉堡套餐薯条(小)-------------------咖啡香芋派麦辣鸡腿堡套餐薯条(大)
可以看出套餐都已经组合完了,而且代码要比直接调用产品类Product简单了很多。
建造者优缺点
优点
- 封装性:使用建造者模式可以使客户端不必知道产品内部的组成部分。
- 独立性,扩展性:具体建造者都相互独立,对系统的扩展非常有利。
- 便于控制细节风险:由于具体的具体建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响。
缺点
- 产生多余的Build(抽象建造者)对象以及Dirextor(导演)类,导致系统庞大。
- 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
建造者的使用场景
- 相同的方法,不同的执行顺序,产生不同的事件结果是,可以采用该模式。
- 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时,则可使用该模式。
- 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效果,这个时间使用建造者模式非常合适。
- 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。
建造者模式与工厂模式区别
与工厂模式相比,建造者模式一般用来创建更为复杂的对象,因为对象的创建过程更为复杂,因此将对象的创建过程独立出来组成一个新的类——导演类。也就是说,工厂模式是将对象的全部创建过程封装在工厂类中,由工厂类向客户端提供最终的产品;而建造者模式中,建造者类一般只提供产品类中各个组件的建造,而将具体建造过程交付给导演类。由导演类负责将各个组件按照特定的规则组建为产品,然后将组建好的产品交付给客户端。
建造者模式关注的是零件类型和装配工艺(顺序),这是它与工厂方法模式最大不同的地方,虽然同为创建类模式,但是注重点不同。