建造者模式浅析

  • 2019 年 10 月 6 日
  • 笔记

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

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

建造者的基本结构如下:

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

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

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

二、Builder模式示例

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

  • 创建一个Meal类,作为Product。
    • 产品包含汉堡列表、饮料列表等参数进行区分
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
    • 支持单个或者多个添加元素
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)
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)
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)
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个香辣鸡腿堡,大杯冰可乐,大杯九珍果汁,热牛奶以及一个香辣鸡翅。

Meal [hamburgerList=[香辣鸡腿堡, 香辣鸡腿堡], juicesList=[大杯冰可乐, 大杯九珍果汁], chipsList=[], otherItemList=[热牛奶, 香辣鸡翅]]

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

三、简化后的构建者模式

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

  • Result
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 + "]";    }      }  
  • 结果类型
package com.wangmengjun.tutorial.designpattern.builder;    public enum ResultType {    SUCCESS, FAILURE, TIMED_OUT, UNKNOWN;  }  
  • ResultBuilder类
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来构建结果。
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,如:

    CacheBuilder.newBuilder()            .maximumSize(10000)            .expireAfterAccess(2, TimeUnit.MINUTES)            .expireAfterWrite(10, TimeUnit.MINUTES)            .initialCapacity(100)            .build();

又如Curator中的:

        CuratorFramework curatorFramework = CuratorFrameworkFactory.                  builder().                  connectString(server.getConnectString()).                  sessionTimeoutMs(1000).                  retryPolicy(new RetryNTimes(3, 1000)).                  build();

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

四、小结

4.1 与抽象工厂的关系

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

4.2 小结

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

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