【HeadFirst 设计模式学习笔记】16 建筑者(Builder)模式拾零
作者:gnuhpc
出处:http://www.cnblogs.com/gnuhpc/
1.概述
这个模式在Head First中没有介绍,大概是因为这个模式和工厂模式有点像。其目的主要是通过创建简单的对象构建一个复杂的对象。
2.举例
举一个例子:创建汽车的相关指标说明。
首先我们创建一个汽车的类:
1: public class Car {2: private boolean powerSteering = false;3: private boolean powerWindow = false;4: private String price = "";
5: public boolean isPowerSteargin() {6: return powerSteering;
7: }8: public void setPowerSteargin(boolean aPowerSteering) {9: this.powerSteering = aPowerSteering;
10: }11: public boolean isPowerWindow() {12: return powerWindow;
13: }14: public void setPowerWindow(boolean aPowerWindow) {15: this.powerWindow = aPowerWindow;
16: }17: public String getPrice() {
18: return price;
19: }20: public void setPrice(String aPrice) {21: this.price = aPrice;
22: }23: //print the output
24: public String toString(){
25: String output = "";26: output += "Power Steering : "+powerSteering+"/n";27: output += "Power Window : "+powerWindow+"/n";28: output += "Price : Rs "+price+"/n";29: return output;
30: }31: }32:
在上边的这个例子中,关于一个汽车的指标说明有三项:Power Steering、Power Window和Price。
然后我们创建一个创建汽车的类CarBuilder :
1: abstract class CarBuilder {2: protected Car car;
3:4: public Car getCar() {
5: return car;
6: }7:8: public void createNewCar() {9: car = new Car();
10: }11: public abstract void setPowerSteering();12: public abstract void setPowerWindow();13: public abstract void setPrice();14: }15:
现在我们创建两个具体汽车类型的创建者:Alto_LX 和 Alto_LXI
1: public class Alto_LX extends CarBuilder{2:3: @Override4: public void setPowerSteering() {5: // TODO Auto-generated method stub
6: car.setPowerSteargin(false);
7: }8:9: @Override10: public void setPowerWindow() {11: // TODO Auto-generated method stub
12: car.setPowerWindow(false);
13: }14:15: @Override16: public void setPrice() {17: // TODO Auto-generated method stub
18: car.setPrice("225000");
19: }20:21: }22:
1: public class Alto_LXI extends CarBuilder{2:3: @Override4: public void setPowerSteering() {5: // TODO Auto-generated method stub
6: car.setPowerSteargin(true);
7: }8:9: @Override10: public void setPowerWindow() {11: // TODO Auto-generated method stub
12: car.setPowerWindow(true);
13: }14:15: @Override16: public void setPrice() {17: // TODO Auto-generated method stub
18: car.setPrice("285000");
19: }20: }21:
最后我们再写一个创建说明并生产汽车的类,这个类组合了具体生产汽车的类,所以该类的一个作用就是生产一部汽车(因为组合而得到的能力),另一个作用是为这个汽车创建相关指标说明(这也是因为组合得到的能力,同时也是进行了封装后提供的接口):
1: public class Specifications {2: private CarBuilder carBuilder;
3: public void setCarBuilder(CarBuilder aCarBuilder){4: carBuilder = aCarBuilder;5: }6: public Car getCar(){
7: return carBuilder.getCar();
8: }9:10: public void constructSpecifications(){11: carBuilder.createNewCar();12: carBuilder.setPowerSteering();13: carBuilder.setPowerWindow();14: carBuilder.setPrice();15: }16: }17:
现在我们就可以造两辆带有指标说明的车了:
1: public class AltoCarBuilderExample {2: public static void main(String[] args) {3: Specifications spec = new Specifications();
4: CarBuilder alto_lx = new Alto_LX();
5: CarBuilder alto_lxi = new Alto_LXI();
6:7: //getting spec for alto lx
8: spec.setCarBuilder(alto_lx);9: spec.constructSpecifications();10: Car alto_lx_car = spec.getCar();11: System.out.println("Specifiction for Alto LX");
12: System.out.println(alto_lx_car.toString());13:14: //getting spec for alto lxi
15: spec.setCarBuilder(alto_lxi);16: spec.constructSpecifications();17: Car alto_lxi_car = spec.getCar();18: System.out.println("Specifiction for Alto LXI");
19: System.out.println(alto_lxi_car.toString());20: }21:22: }23:
我们可以看到,首先我们实例化了一个创建说明的类,并且实例化了两个生产汽车的类。随后利用创建汽车能力的创建说明类来完成说明和汽车的构造。
抽象一下,UML图为:
本例中的Specification就是该图中Director。
3.与工厂方法(或抽象工厂方法)比较
该方法强调利用封装一步步完成一个复杂对象的构建,比如本例中的Specifications就是通过创建汽车、创建三项说明来完成汽车的最终构建的。而抽象工厂方法强调构建一系列产品对象,不管其复杂与否。另外,工厂方法还会根据传入的参数进行对象构建,这个建筑者模式中并没有。
在Effective Java, 2nd Edition中提到:The builder pattern is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters.
我们经常见过这样设计的类:
1: Pizza(int size) { ... }
2: Pizza(int size, boolean cheese) { ... }3: Pizza(int size, boolean cheese, boolean pepperoni) { ... }4: Pizza(int size, boolean cheese, boolean pepperoni, boolean bacon) { ... }5:
你可以做如下改进:
1: Pizza pizza = new Pizza(12);
2: pizza.setCheese(true);
3: pizza.setPepperoni(true);
4: pizza.setBacon(true);
这样做也有问题:通过若干步创建的pizza可能会导致对象创建的不完整,并且对于线程安全还需要多多考量。
此时我们可以使用构建者模式(此处使用嵌套类,其实和组合是一个效果):
1: public class Pizza {2: private int size;3: private boolean cheese;4: private boolean pepperoni;5: private boolean bacon;6:7: public static class Builder {8: //required
9: private final int size;10:11: //optional
12: private boolean cheese = false;13: private boolean pepperoni = false;14: private boolean bacon = false;15:16: public Builder(int size) {17: this.size = size;
18: }19:20: public Builder cheese(boolean value) {21: cheese = value;22: return this;23: }24:25: public Builder pepperoni(boolean value) {26: pepperoni = value;27: return this;28: }29:30: public Builder bacon(boolean value) {31: bacon = value;32: return this;33: }34:35: public Pizza build() {
36: return new Pizza(this);37: }38: }39:40: private Pizza(Builder builder) {
41: size = builder.size;42: cheese = builder.cheese;43: pepperoni = builder.pepperoni;44: bacon = builder.bacon;45: }46: }47:
现在我们创建一个Pizza就是如下的方式:
1: Pizza pizza = new Pizza.Builder(12).cheese(true).pepperoni(true).bacon(true).build();
这个例子可以与工厂模式里面的例子对比一下,就知道这两个模式的区别了。
Java中的DocumentBuilderFactory , StringBuffer, StringBuilder 都是这个模式的例子。