Java - GoF设计模式详解3(建造者模式)
作者:hangge | 2023-02-28 08:50
三、建造者模式
1,基本介绍
(1)建造者模式(Builder)可以把复杂对象的创建与表示分离,使得同样的创建过程可以创建不同的表示。建造者模式与抽象工厂模式非常类似,但建造者模式是逐步地构造出一个复杂对象,并在最后返回对象的实例。
(2)该模式中包含的角色及其职责如下:
- Product(产品角色):表示被构造的复杂对象。
- Builder(抽象建造者):为创建一个产品对象的各个部件指定抽象接口。
- ConcreteBuilder(具体建造者):实现 Builder 的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并提供一个检索产品的接口。
- Director(指挥者):构造一个使用 Builder 接口的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程

2,使用样例
(1)这里我们以肯德基套餐为例演示建造者模式的使用。首先我们创建一个 SetMeal 套餐类,也就是最终要创建的产品类,里面包含主食和饮料两个部件(属性)。
public class SetMeal {
private String food;
private String drink;
public String getFood() {
return food;
}
public void setFood(String food) {
this.food = food;
}
public String getDrink() {
return drink;
}
public void setDrink(String drink) {
this.drink = drink;
}
}
(2)接着创建一个 SetMealBuilder 套餐建造者类(即抽象建造者类),它声明了两个抽象的部件组装方法 buildFood() 和 buildDrink(),同时定义了 SetMeal 产品对象,并提供了工厂方法 getSetMeal() 用于返回 SetMeal 对象。
public abstract class SetMealBuilder {
protected SetMeal setMeal = new SetMeal();
public abstract void buildFood();
public abstract void buildDrink();
public SetMeal getSetMeal() {
return setMeal;
}
}
(3)然后创建两个具体的建造者:香辣鸡腿堡套餐建造者、奥尔良烤翅套餐。它们是抽象建造者类的子类,实现了在抽象建造者中声明的部件组装方法,为产品设置不同的部件内容。
//香辣鸡腿堡套餐建造者
public class BurgerSetMealBuilder extends SetMealBuilder{
@Override
public void buildFood() {
setMeal.setFood("1个香辣鸡腿堡");
}
@Override
public void buildDrink() {
setMeal.setDrink("1杯可乐");
}
}
//奥尔良烤翅套餐
public class ChickenSetMealBuilder extends SetMealBuilder{
@Override
public void buildFood() {
setMeal.setFood("1份奥尔良烤翅");
}
@Override
public void buildDrink() {
setMeal.setDrink("1杯九珍果汁");
}
}
(4)接着我们创建一个服务员类(即指挥者),其中定义了一个抽象建造者对象,而具体建造者类型由客户端指定;同时在其 construct() 方法中调用建造者对象的部件组装方法和工厂方法,用于向客户端返回1份包含主食和饮料的完整套餐。
public class Waiter {
private SetMealBuilder builder;
public void setBuilder(SetMealBuilder builder) {
this.builder = builder;
}
public SetMeal construct() {
builder.buildFood();
builder.buildDrink();
return builder.getSetMeal();
}
}
(5)最后我们测试一下,我们只需要的将对应的套餐建造者对象传入指挥者对象中,然后调用指挥者的 construct() 方法即可自动组装并返回相应的套餐。
public class Test {
public static void main(String[] args) {
Waiter waiter = new Waiter();
//第一个套餐
SetMealBuilder builder1 = new ChickenSetMealBuilder();
waiter.setBuilder(builder1);
SetMeal setMeal1 = waiter.construct();
System.out.println("第一个套餐包含:" + setMeal1.getFood() + "," + setMeal1.getDrink());
//第二个套餐
SetMealBuilder builder2 = new BurgerSetMealBuilder();
waiter.setBuilder(builder2);
SetMeal setMeal2 = waiter.construct();
System.out.println("第二个套餐包含:" + setMeal2.getFood() + "," + setMeal2.getDrink());
}
}
附一:建造者模式在 JDK 中的应用(StringBuilder、StringBuffer)
(1)JDK 的 StringBuilder 和 StringBuffer 类中提供了 append() 追加方法,这是一种链式创建对象的方法,开放构造步骤,最后调用了 toString() 方法就可获得完整的对象,例如:
提示:相对于 StringBuilder,StringBuffer 的 append 方法加上了 synchronized 关键字。在多线程场景下,使用 StringBuffer 保证线程安全,其他场景则使用 StringBuilder 获得更好的性能
StringBuilder sb = new StringBuilder()
.append("1234")
.append("abcd")
.append("+-*/");
String s = sb.toString();
(2)以 StringBuilder 为例,它的继承结构如下图所示:
- Appendable 接口定义了多个 append 抽象方法,即 Appendable 为抽象建造者。
- AbstractStringBuilder 实现了 Appendable 接口方法,已经是一个具体建造者,但它是一个抽象类不能实例化。
- StringBuilder 继承了 AbstractStringBuilder,它通过调用父类 AbstractStringBuilder 的 append 方法的形式重写了 append 方法。因而,StringBuilder 相当于 Appendable 抽象构建者的具体构建者,同时又充当了指挥者(Director)的角色。

附二:MyBatis 中的建造者模式
(1)MyBatis 中 SqlSessionFactoryBuiler 类用到了建造者模式,SqlSessionFactory 是通过 SqlSessionFactoryBuilder 创建的,代码如下。
public class SqlSessionFactoryBuilder {
...
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}
(2)但是,Configuration 类的属性非常多,设置起来非常繁杂。为了简便设置,在 SqlSessionFactoryBuilder 类中有个重载的 build 方法便通过 XMLConfigBuilder 的 parse() 方法构建 Configuration 实例。
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// 创建建造者 XMLConfigBuilder的 实例
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
// XMLConfigBuilder 的 parse() 创建 Configuration 实例
return build(parser.parse());
} catch (Exception e) {
// 捕获异常
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
// 重置错误
ErrorContext.instance().reset();
try {
// 释放资源
inputStream.close();
} catch (IOException e) {
// IO 错误不进行处理
}
}
}
}
(3)XMLConfigBuilder 负责 Configuration 各个组建的创建和装配,整个装配流程如下:
package org.apache.ibatis.builder.xml;
...
public class XMLConfigBuilder extends BaseBuilder {
// 解析配置累
private void parseConfiguration(XNode root) {
try {
// issue #117 read properties first
// 1.读取XML的<properties>标签
propertiesElement(root.evalNode("properties"));
// 2. 读取XML的<settings>标签
Properties settings = settingsAsProperties(root.evalNode("settings"));
// 3. 加载自定义的配置
loadCustomVfs(settings);
loadCustomLogImpl(settings);
// 4. 加载XML的<typeAliases> 标签
typeAliasesElement(root.evalNode("typeAliases"));
// 5. 加载XML的 <plugins> 标签
pluginElement(root.evalNode("plugins"));
// 6. 加载XML的<objectFactory> 标签
objectFactoryElement(root.evalNode("objectFactory"));
// 7. 加载XML的<objectWrapperFactory>标签
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
// 8. 加载XML的<reflectorFactory> 标签
reflectorFactoryElement(root.evalNode("reflectorFactory"));
// 9. 更新设置
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
// 10. 加载XML的<environments> 标签
environmentsElement(root.evalNode("environments"));
// 11. 加载XML的 <databaseIdProvider> 标签
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
// 12. 加载XML的 <typeHandlers> 标签
typeHandlerElement(root.evalNode("typeHandlers"));
// 13. 加载XML的 <mappers> 标签
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
}
(4)我们可以看出:
- XMLConfigBuilder 类负责创建复杂对象 Configuration,XMLConfigBuilder 可以视为具体建造者角色,Configuration 相当于产品。XMLConfigBuilder 继承自 BaseBuilder,所以 BaseBuilder 相当于是抽象建造者的角色。
- 而 SqlSessionFactoryBuilder 则是以封装形式根据不同的输⼊参数构建 SqlSessionFactory 实例,又相当于一个简化的建造者模式。
全部评论(0)