0%

【设计模式】Builder Pattern 建造者模式

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

建造者模式

将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。
它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。
它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。

意图

  • 将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同表示。

解决问题

  1. 需要生成的对象具有复杂的内部结构。
  2. 需要生成的对象内部属性本身相互依赖。

何时使用?

一些基本部件不会变,而其组合经常变化的时候。
当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。

应用环境举例

  1. 去肯德基,汉堡、可乐、薯条、炸鸡翅等食物为不变的,而其组合是经常变化的,生成出所谓的”套餐”。
  2. JAVA 中的 StringBuilder。

优点

  1. 封装性好,构建和表示分离。
  2. 扩展性好,各个具体的建造者相互独立,有利于系统的解耦。
  3. 建造者独立,易扩展。
  4. 便于控制细节风险。

缺点

  1. 产品必须有共同点,范围有限制。
  2. 如内部变化复杂,会有很多的建造类,如果产品内部发生变化,则建造者也要同步修改,后期维护成本较大。

注意

与工厂模式的区别是:建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用。

类图 / 理解

  • 产品角色(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
    21
    class 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
    11
    abstract 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
    13
    public 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
    13
    class 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
    8
    public 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 食物项目
    1
    2
    3
    4
    5
    public interface Item {
    public String name(); //名称
    public Packing packing();//包装方法
    public float price(); //价格
    }
    Packing.java 打包
    1
    2
    3
    public interface Packing {
    public String pack(); //
    }
  • 创建实现 Packing 接口的实体类。
    Wrapper.java 包装纸
    1
    2
    3
    4
    5
    6
    7
    public class Wrapper implements Packing {

    @Override
    public String pack() {
    return "Wrapper";
    }
    }
    Bottle.java 瓶子
    1
    2
    3
    4
    5
    6
    7
    public class Bottle implements Packing {

    @Override
    public String pack() {
    return "Bottle";
    }
    }
  • 创建实现 Item 接口的抽象类,该类提供了默认的功能。
    Burger.java 汉堡
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public abstract class Burger implements Item {

    @Override
    public Packing packing() {
    return new Wrapper();
    }

    @Override
    public abstract float price();
    }
    ColdDrink.java 冷饮
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public abstract class ColdDrink implements Item {

    @Override
    public Packing packing() {
    return new Bottle();
    }

    @Override
    public abstract float price();
    }
  • 创建扩展了 Burger 和 ColdDrink 的实体类。
    VegBurger.java 素食汉堡
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class VegBurger extends Burger {

    @Override
    public float price() {
    return 25.0f;
    }

    @Override
    public String name() {
    return "Veg Burger";
    }
    }
    ChickenBurger.java 鸡肉汉堡包
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class ChickenBurger extends Burger {

    @Override
    public float price() {
    return 50.5f;
    }

    @Override
    public String name() {
    return "Chicken Burger";
    }
    }
    Coke.java 可乐
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Coke extends ColdDrink {

    @Override
    public float price() {
    return 30.0f;
    }

    @Override
    public String name() {
    return "Coke";
    }
    }
    Pepsi.java 百事可乐
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Pepsi extends ColdDrink {

    @Override
    public float price() {
    return 35.0f;
    }

    @Override
    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
    26
    import 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
    16
    public 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.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public 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());
    }
    }

感谢查阅

建议参考
另一种理解方式
这篇文章