建造者模式是一种创建型的模式,其意图是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
一、建造者模式的基本介绍
建造者的基本结构如下:
- 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个香辣鸡腿堡,大杯冰可乐,大杯九珍果汁,热牛奶以及一个香辣鸡翅。
代码语言:javascript复制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,如:
代码语言: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 小结
建造者模式的意图是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是体现局部和整体关系的,产品是一步步构建,最终形成的一定是一个整体。
针对有诸多参数的复杂对象的创建,可能包含多个构造函数。在这种场景下,使用建造者模式的来进行创建对象,更加直观和灵活。