概述
在现实生活或软件系统中,都存在一些由多个部分组成的复杂类,例如一个KFC套餐,它里面包括食品(汉堡,薯条,蛋挞等),饮料(可乐,雪碧等),不同套餐的食品和饮料的构成也不同。作为客户的我们无需关注这个套餐是如何生成的,我们只需要与服务员交流,表明自己需要哪种套餐,这样服务员(指挥者)就会通过 操作生成该套餐的食品,饮料的机器,然后返回套餐。
简单的的说,建造者模式是指用户只通过指定复杂对象(套餐)的类型和内容(套餐的类型和其不同组成)就可以构建它们,用户无需知道内部的具体构建细节。
在建造者模式的主要角色有:
- 产品角色,如本例中的套餐,它包含食物对象和饮料对象。
- 抽象建造者,本例中生成食物和饮料的机器的大致功能描述
- 具体创建者,本例中生成不同食物和不通过饮料的机器
- 指挥者:它包含抽象建造者实例对象。它主要负责隔离客户与对象的生产过程 和 负责控制产品对象的生产过程。如本例中的服务员。
优点
(1)用户不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
(2)每一个具体建造者都相对独立,而与其他的具体建造者无关,用户使用不同的具体建造者即可得到不同的产品对象 。
(3)增加新的具体建造者无须修改原有类库的代码,符合 “开闭原则”。
什么情况下不要用建造者模式?
(1)产品差异性很大的情况:建造者模式所创建的产品一般具有较多的共同点,其组成部分相似。
(2)产品内部变化很复杂的情况:如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类,导致系统庞大。
工厂模式与建造者模式的区别
(1)在工厂模式下,一个工厂生产一个/一组产品,该模式下不关系构建过程,只需知道该产品由哪些工厂组成即可。它关注的是一个产品整体。
(2)在建造者模式下,一个具体产品的产生是依赖于各个部件的产生和装配顺序。它关注的是”由零件一步一步地组装出产品对象“。它关注的是产品组成部分的创建过程。
建造者模式示例
以KFC套餐为例,一个套餐分为食品和饮料,不同套餐的食品和饮料不同。
一个套餐就是一个产品角色,套餐里有食品和饮料。
public class Meal {
private String food;
private String drink;
//省略get/set方法
}
抽象建造者。它包含一个产品角色,它大致描述了它有什么功能:生产食品和饮料。即生产不同套餐的机器的大致描述
public abstract class MealBuilder {
Meal meal = new Meal();
public abstract void buildFood();
public abstract void buildDrink();
public Meal getMeal(){ return meal; }
}
具体建造者,它实现了抽象建造者的三个生产功能,即生产不同套餐内容的机器。
public class MealA extends MealBuilder{
public void buildDrink() {
meal.setDrink("可乐");
}
public void buildFood() {
meal.setFood("薯条");
}
}
public class MealB extends MealBuilder{
public void buildDrink() {
meal.setDrink("柠檬果汁");
}
public void buildFood() {
meal.setFood("鸡翅");
}
}
指挥者。它包含一个抽象建造者实例builder。它通过builder来返回生产的产品,就好比一个服务员KFCWaiter操作不同机器MealBuilder 来生成产品(套餐),并返回 产品。
public class KFCWaiter {
private MealBuilder mealBuilder;
public KFCWaiter(MealBuilder mealBuilder) {
this.mealBuilder = mealBuilder;
}
public Meal construct(){
//准备食物
mealBuilder.buildFood();
//准备饮料
mealBuilder.buildDrink();
//准备完毕,返回一个完整的套餐给客户
return mealBuilder.getMeal();
}
}
测试一下:
public class Test {
public static void main(String[] args) {
//套餐A
MealA a = new MealA();
//准备套餐A的服务员
KFCWaiter waiter = new KFCWaiter(a);
//获得套餐
Meal mealA = waiter.construct();
System.out.print("套餐A的组成部分:");
System.out.println("食物:"+mealA.getFood()+"; "+"饮品:"+mealA.getDrink());
}
}
StringBuilder 中的建造者模式
下图是StringBuilder 的继承关系图

Appendable 接口方法如下,
public interface Appendable {
Appendable append(CharSequence csq) throws IOException;
Appendable append(CharSequence csq, int start, int end) throws IOException;
Appendable append(char c) throws IOException;
}
StringBuilder 的append方法如下所示,它调用了父类AbstractStringBuilder的append方法。
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence {
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
}
AbstractStringBuilder 的append方法如下:
abstract class AbstractStringBuilder implements Appendable, CharSequence {
char[] value;
int count;
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
}
因此,Appendable接口是抽象建造者,定义建造方法append。建造方法的实现由AbstractStringBuilder 类完成,它是具体建造者,它的子类StringBuilder 充当了指挥者角色。