建造者模式理解剖析以及应用

建造者模式
将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。
它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。
它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。
意图
- 将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同表示。
解决问题
- 需要生成的对象具有复杂的内部结构。
- 需要生成的对象内部属性本身相互依赖。
何时使用?
一些基本部件不会变,而其组合经常变化的时候。
当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。
应用环境举例
- 去肯德基,汉堡、可乐、薯条、炸鸡翅等食物为不变的,而其组合是经常变化的,生成出所谓的”套餐”。
- JAVA 中的 StringBuilder。
优点
- 封装性好,构建和表示分离。
- 扩展性好,各个具体的建造者相互独立,有利于系统的解耦。
- 建造者独立,易扩展。
- 便于控制细节风险。
缺点
- 产品必须有共同点,范围有限制。
- 如内部变化复杂,会有很多的建造类,如果产品内部发生变化,则建造者也要同步修改,后期维护成本较大。
注意
与工厂模式的区别是:建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用。
类图 / 理解

- 产品角色(Product):
它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。 - 抽象建造者(Builder):
它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。 - 具体建造者(Concrete Builder):
实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。 - 指挥者(Director):
它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。
实现
- 产品角色:包含多个组成部件的复杂对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21class Product {
private String partA;
private String partB;
private String partC;
public void setPartA(String partA) {
this.partA = partA;
}
public void setPartB(String partB) {
this.partB = partB;
}
public void setPartC(String partC) {
this.partC = partC;
}
public void show() {
//显示产品的特性
}
} - 抽象建造者:包含创建产品各个子部件的抽象方法。
1
2
3
4
5
6
7
8
9
10
11abstract class Builder {
//创建产品对象
protected Product product = new Product();
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
//返回产品对象
public Product getResult() {
return product;
}
} - 具体建造者:实现了抽象建造者接口。
1
2
3
4
5
6
7
8
9
10
11
12
13public class ConcreteBuilder extends Builder {
public void buildPartA() {
product.setPartA("建造 PartA");
}
public void buildPartB() {
product.setPartB("建造 PartB");
}
public void buildPartC() {
product.setPartC("建造 PartC");
}
} - 指挥者:调用建造者中的方法完成复杂对象的创建。
1
2
3
4
5
6
7
8
9
10
11
12
13class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
//产品构建与组装方法
public Product construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
return builder.getResult();
}
} - 客户类
1
2
3
4
5
6
7
8public class Client {
public static void main(String[] args) {
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
Product product = director.construct();
product.show();
}
}
实例
理解
我们假设一个快餐店的商业案例,其中,一个典型的套餐可以是一个汉堡(Burger)和一杯冷饮(Cold drink)。
- 汉堡(Burger)可以是素食汉堡(Veg Burger)或鸡肉汉堡(Chicken Burger),它们是包在纸盒中。
- 冷饮(Cold drink)可以是可口可乐(coke)或百事可乐(pepsi),它们是装在瓶子中。
我们将创建
一个表示食物条目的 Item 接口 和 实现 Item 接口的实体类
以及
一个表示食物包装的 Packing 接口 和 实现 Packing 接口的实体类,
汉堡是包在纸盒中,冷饮是装在瓶子中。
然后我们创建
一个 Meal 类,带有 Item 的 ArrayList 和一个通过结合 Item 来创建不同类型的 Meal 对象的 MealBuilder。
BuilderPatternDemo 类使用 MealBuilder 来创建一个 Meal。
代码
- 创建一个表示食物条目和食物包装的接口。
Item.java 食物项目Packing.java 打包1
2
3
4
5public interface Item {
public String name(); //名称
public Packing packing();//包装方法
public float price(); //价格
}1
2
3public interface Packing {
public String pack(); //
} - 创建实现 Packing 接口的实体类。
Wrapper.java 包装纸Bottle.java 瓶子1
2
3
4
5
6
7public class Wrapper implements Packing {
public String pack() {
return "Wrapper";
}
}1
2
3
4
5
6
7public class Bottle implements Packing {
public String pack() {
return "Bottle";
}
} - 创建实现 Item 接口的抽象类,该类提供了默认的功能。
Burger.java 汉堡ColdDrink.java 冷饮1
2
3
4
5
6
7
8
9
10public abstract class Burger implements Item {
public Packing packing() {
return new Wrapper();
}
public abstract float price();
}1
2
3
4
5
6
7
8
9
10public abstract class ColdDrink implements Item {
public Packing packing() {
return new Bottle();
}
public abstract float price();
} - 创建扩展了 Burger 和 ColdDrink 的实体类。
VegBurger.java 素食汉堡ChickenBurger.java 鸡肉汉堡包1
2
3
4
5
6
7
8
9
10
11
12public class VegBurger extends Burger {
public float price() {
return 25.0f;
}
public String name() {
return "Veg Burger";
}
}Coke.java 可乐1
2
3
4
5
6
7
8
9
10
11
12public class ChickenBurger extends Burger {
public float price() {
return 50.5f;
}
public String name() {
return "Chicken Burger";
}
}Pepsi.java 百事可乐1
2
3
4
5
6
7
8
9
10
11
12public class Coke extends ColdDrink {
public float price() {
return 30.0f;
}
public String name() {
return "Coke";
}
}1
2
3
4
5
6
7
8
9
10
11
12public class Pepsi extends ColdDrink {
public float price() {
return 35.0f;
}
public String name() {
return "Pepsi";
}
} - 创建一个 Meal 类,带有上面定义的 Item 对象。
Meal.java 一次点餐1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26import java.util.ArrayList;
import java.util.List;
public class Meal {
private List<Item> items = new ArrayList<Item>();
public void addItem(Item item){
items.add(item);
}
public float getCost(){
float cost = 0.0f;
for (Item item : items) {
cost += item.price();
}
return cost;
}
public void showItems(){
for (Item item : items) {
System.out.print("Item : "+item.name());
System.out.print(", Packing : "+item.packing().pack());
System.out.println(", Price : "+item.price());
}
}
} - 创建一个 MealBuilder 类,实际的 builder 类负责创建 Meal 对象。
MealBuilder.java 构建点餐1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class MealBuilder {
public Meal prepareVegMeal (){
Meal meal = new Meal();
meal.addItem(new VegBurger());
meal.addItem(new Coke());
return meal;
}
public Meal prepareNonVegMeal (){
Meal meal = new Meal();
meal.addItem(new ChickenBurger());
meal.addItem(new Pepsi());
return meal;
}
} - BuiderPatternDemo 使用 MealBuilder 来演示建造者模式(Builder Pattern)。
BuilderPatternDemo.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class BuilderPatternDemo {
public static void main(String[] args) {
MealBuilder mealBuilder = new MealBuilder();
Meal vegMeal = mealBuilder.prepareVegMeal();
System.out.println("Veg Meal");
vegMeal.showItems();
System.out.println("Total Cost: " +vegMeal.getCost());
Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
System.out.println("\n\nNon-Veg Meal");
nonVegMeal.showItems();
System.out.println("Total Cost: " +nonVegMeal.getCost());
}
}