建造者模式浅析

2019-09-24 11:02:42 浏览数 (1)

建造者模式是一种创建型的模式,其意图是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

一、建造者模式的基本介绍

建造者的基本结构如下:

  • Builder
    • 为创建一个Product对象的各个部件指定抽象接口。
  • ConcreteBuilder
    • 实现Builder的接口以构造和装载该产品的各个部件
    • 定义并明确它所创建的表示
  • Director
    • 构造一个使用Builder接口的对象
  • Product
    • 表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。
    • 包括定义组成部件的类,包括将这些部件装配成最终产品的接口。

Note:建造者模式是体现局部和整体关系的,产品是一步步构建,最终形成的一定是一个整体。

就比如顾客去餐厅购买一份儿童餐,跟收银员说要汉堡、饮料、甜甜圈有额外的玩具等,最终顾客得到是包含所有的儿童餐,是一个整体。

二、Builder模式示例

接下来,我们以上述点餐的例子编写一个建造者模式的示例代码。

  • 创建一个Meal类,作为Product。
    • 产品包含汉堡列表、饮料列表等参数进行区分
代码语言:javascript复制
package com.wangmengjun.tutorial.designpattern.builder;

import java.util.ArrayList;
import java.util.List;

public class Meal {
  
  private List<String> hamburgerList = new ArrayList<>();
  
  private List<String> juicesList = new ArrayList<>();
  
  private List<String> chipsList= new ArrayList<>();
  
  private List<String> otherItemList= new ArrayList<>();

  /**
   * @return the hamburgerList
   */
  public List<String> getHamburgerList() {
    return hamburgerList;
  }

  /**
   * @param hamburgerList the hamburgerList to set
   */
  public void setHamburgerList(List<String> hamburgerList) {
    this.hamburgerList = hamburgerList;
  }

  /**
   * @return the juicesList
   */
  public List<String> getJuicesList() {
    return juicesList;
  }

  /**
   * @param juicesList the juicesList to set
   */
  public void setJuicesList(List<String> juicesList) {
    this.juicesList = juicesList;
  }

  /**
   * @return the chipsList
   */
  public List<String> getChipsList() {
    return chipsList;
  }

  /**
   * @param chipsList the chipsList to set
   */
  public void setChipsList(List<String> chipsList) {
    this.chipsList = chipsList;
  }

  /**
   * @return the otherItemList
   */
  public List<String> getOtherItemList() {
    return otherItemList;
  }

  /**
   * @param otherItemList the otherItemList to set
   */
  public void setOtherItemList(List<String> otherItemList) {
    this.otherItemList = otherItemList;
  }

  @Override
  public String toString() {
    return "Meal [hamburgerList="   hamburgerList   ", juicesList="   juicesList   ", chipsList="   chipsList
          ", otherItemList="   otherItemList   "]";
  }
  
  
}
  • 创建一个Builder
    • 支持单个或者多个添加元素
代码语言:javascript复制
package com.wangmengjun.tutorial.designpattern.builder;

import java.util.List;

public abstract class  Builder {

  public abstract void hamburger(String name);
  
  public abstract void juice(String name);
  
  public abstract void chips(String name);
  
  public abstract void other(String name);
  
  
  public abstract void hamburger(List<String> names);
  
  public abstract void juice(List<String> names);
  
  public abstract void chips(List<String> names);
  
  public abstract void other(List<String> names);
  
  public abstract Meal build();
  
}
  • 创建一个RestaurantCrew类(ConcreteBuilder)
代码语言:javascript复制
package com.wangmengjun.tutorial.designpattern.builder;

import java.util.List;

public class RestaurantCrew extends Builder {

  private Meal meal;
  
  public RestaurantCrew() {
    this.meal = new Meal();
  }

  @Override
  public void hamburger(String name) {
    meal.getHamburgerList().add(name);
    
  }

  @Override
  public void juice(String name) {
    meal.getJuicesList().add(name);
    
  }

  @Override
  public void chips(String name) {
    meal.getChipsList().add(name);
    
  }

  @Override
  public void other(String name) {
    meal.getOtherItemList().add(name);
    
  }

  @Override
  public void hamburger(List<String> names) {
    meal.getHamburgerList().addAll(names);
    
  }

  @Override
  public void juice(List<String> names) {
    meal.getJuicesList().addAll(names);
    
  }

  @Override
  public void chips(List<String> names) {
    meal.getChipsList().addAll(names);
    
  }

  @Override
  public void other(List<String> names) {
    meal.getOtherItemList().addAll(names);
    
  }
  
  @Override
  public Meal build() {
    return meal;
  }

}
  • 创建一个Cashier类(Director)
代码语言:javascript复制
package com.wangmengjun.tutorial.designpattern.builder;

import java.util.List;

public class Cashier {

  private Builder builder;
  
  public Cashier(Builder builder) {
    this.builder = builder;
  }

  public Cashier(Builder builder, List<String> juicesList, List<String> hamburgerList, List<String> otherList) {
    this.builder = builder;
  }
  
  public void construct( List<String> juicesList, List<String> hamburgerList, List<String> otherList) {
    this.builder.hamburger(hamburgerList);
    this.builder.juice(juicesList);
    this.builder.other(otherList);
  }

}
  • 创建一个Customer类(Client)
代码语言:javascript复制
package com.wangmengjun.tutorial.designpattern.builder;

import java.util.Arrays;

public class Customer {

  public static void main(String[] args) {
    order();
  }
  
  private static void order() {
    //Builder
    Builder builder = new RestaurantCrew();
    //Director
    Cashier defaultCashier = new Cashier(builder);
    defaultCashier.construct(Arrays.asList("大杯冰可乐","大杯九珍果汁"), Arrays.asList("香辣鸡腿堡","香辣鸡腿堡"), Arrays.asList("热牛奶","香辣鸡翅"));
    
    //Meal [hamburgerList=[香辣鸡腿堡, 香辣鸡腿堡], juicesList=[大杯冰可乐, 大杯九珍果汁], chipsList=[], otherItemList=[热牛奶, 香辣鸡翅]]
    Meal defaultMeal = builder.build();
    System.out.println(defaultMeal);
  }
}

运行Customer类之后,就会获取一份点餐后的结果,包含了2个香辣鸡腿堡,大杯冰可乐,大杯九珍果汁,热牛奶以及一个香辣鸡翅。

代码语言:javascript复制
Meal [hamburgerList=[香辣鸡腿堡, 香辣鸡腿堡], juicesList=[大杯冰可乐, 大杯九珍果汁], chipsList=[], otherItemList=[热牛奶, 香辣鸡翅]]

这样,一个Builder模式的示例就完成了。

三、简化后的构建者模式

一般在使用的情况下,Builder只有一个,且不需要Diractor的。如下面一个结果返回的示例:

  • Result
代码语言:javascript复制
package com.wangmengjun.tutorial.designpattern.builder;

public class Result {

  private ResultType type;
  
  private String code;
  
  private String message;
  
  private Object data;

  /**
   * @return the type
   */
  public ResultType getType() {
    return type;
  }

  /**
   * @param type the type to set
   */
  public void setType(ResultType type) {
    this.type = type;
  }

  /**
   * @return the code
   */
  public String getCode() {
    return code;
  }

  /**
   * @param code the code to set
   */
  public void setCode(String code) {
    this.code = code;
  }

  /**
   * @return the message
   */
  public String getMessage() {
    return message;
  }

  /**
   * @param message the message to set
   */
  public void setMessage(String message) {
    this.message = message;
  }

  /**
   * @return the data
   */
  public Object getData() {
    return data;
  }

  /**
   * @param data the data to set
   */
  public void setData(Object data) {
    this.data = data;
  }

  @Override
  public String toString() {
    return "Result [type="   type   ", code="   code   ", message="   message   ", data="   data   "]";
  }
  
  
}
  • 结果类型
代码语言:javascript复制
package com.wangmengjun.tutorial.designpattern.builder;

public enum ResultType {
  SUCCESS, FAILURE, TIMED_OUT, UNKNOWN;
}
  • ResultBuilder类
代码语言:javascript复制
package com.wangmengjun.tutorial.designpattern.builder;

public class ResultBuilder {

  private ResultType type;
  private String code;
  private String message;
  private Object data;
  
  public static ResultBuilder newInstance() {
    return new ResultBuilder();
  }
  
  public ResultBuilder type(ResultType type) {
    this.type = type;
    return this;
  }
  
  
  public ResultBuilder code(String code) {
    this.code = code;
    return this;
  }
  
  
  public ResultBuilder message(String message) {
    this.message = message;
    return this;
  }
  
  public ResultBuilder data(Object data) {
    this.data = data;
    return this;
  }
  
  public Result build() {
    Result result = new Result();
    result.setCode(code);
    result.setData(data);
    result.setMessage(message);
    result.setType(type);
    return result;
  }
}
  • 测试一下,使用Builder来构建结果。
代码语言:javascript复制
package com.wangmengjun.tutorial.designpattern.builder;

public class BuilderMain {

  public static void main(String[] args) {
    Result result1 = ResultBuilder.newInstance().type(ResultType.SUCCESS)
                  .message("success message")
                  .code("code123456")
                  .build();
    //Result [type=SUCCESS, code=code123456, message=success message, data=null]
    System.out.println(result1);
    
    
    Result result2 = ResultBuilder.newInstance().type(ResultType.TIMED_OUT)
        .message("timed-out message")
        .code("timedout123456")
        .data("abcdef")
        .build();
    //Result [type=TIMED_OUT, code=timedout123456, message=timed-out message, data=abcdef]
    System.out.println(result2);
  }
}

这种方式是否似曾相识,比如Guava的CacheBuilder,如:

代码语言:javascript复制
    CacheBuilder.newBuilder()
          .maximumSize(10000)
          .expireAfterAccess(2, TimeUnit.MINUTES)
          .expireAfterWrite(10, TimeUnit.MINUTES)
          .initialCapacity(100)
          .build();

又如Curator中的:

代码语言:javascript复制
        CuratorFramework curatorFramework = CuratorFrameworkFactory.
                builder().
                connectString(server.getConnectString()).
                sessionTimeoutMs(1000).
                retryPolicy(new RetryNTimes(3, 1000)).
                build();

这种流式风格的赋值方式更加直观和灵活。

四、小结

4.1 与抽象工厂的关系

抽象工厂和建造者模式相似,因为它也可以创建复杂的对象。主要的区别是建造是者模式着重于一步一步构建一个复杂对象。而抽象工厂着重于多个系列的产品对象(简单的或者复杂的)。建造者模式在最后的一步返回产品,而对于抽象工厂来说,产品是立即返回的。

4.2 小结

建造者模式的意图是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是体现局部和整体关系的,产品是一步步构建,最终形成的一定是一个整体。

针对有诸多参数的复杂对象的创建,可能包含多个构造函数。在这种场景下,使用建造者模式的来进行创建对象,更加直观和灵活。

0 人点赞