现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

HeadFirst 设计模式学习笔记17–建筑者(Builder)模式拾零

2012-07-19 08:10 工业·编程 ⁄ 共 4733字 ⁄ 字号 暂无评论

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:  @Override
  4:  public void setPowerSteering() {
  5:  // TODO Auto-generated method stub
  6:  car.setPowerSteargin(false);
  7:  }
  8:  
  9:  @Override
 10:  public void setPowerWindow() {
 11:  // TODO Auto-generated method stub
 12:  car.setPowerWindow(false);
 13:  }
 14:  
 15:  @Override
 16:  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:  @Override
  4:  public void setPowerSteering() {
  5:  // TODO Auto-generated method stub
  6:  car.setPowerSteargin(true);
  7:  }
  8:  
  9:  @Override
 10:  public void setPowerWindow() {
 11:  // TODO Auto-generated method stub
 12:  car.setPowerWindow(true);
 13:  }
 14:  
 15:  @Override
 16:  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图为:

Builder_pattern

本例中的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();

这个例子可以与工厂模式里面的例子对比一下,就知道这两个模式的区别了。

给我留言

留言无头像?