设计模式-建造者模式

1. 概念

  • 建造者模式(Builder Pattern)又叫生成器模式,是一种创建型设计模式,用于将复杂对象的构建过程与其表示分离,以便相同的构建过程可以创建不同的表示。这种模式特别适用于创建那些具有多个组成部分、步骤复杂或者产品具有多种不同变化的对象。

2. 原理结构图

在这里插入图片描述

  • 原理结构图说明
    • 产品(Product):这是最终要创建的复杂对象,它由多个部件组成,这些部件可能有不同的创建和组装过程。
    • 抽象建造者(Builder):这个角色定义了创建产品对象的各个部件所需的抽象接口。通常会声明两类方法,一类是buildXXX()方法,用于创建复杂对象的各个部分;另一类是getResult()方法,用于返回最终的复杂对象。
    • 具体建造者(ConcreteBuilder):这个角色实现了抽象建造者的接口或继承了抽象建造者的类。它负责实现各个部件的具体构造和装配方法,并定义所创建的复杂对象。具体建造者还可能提供一个方法来返回创建好的复杂对象。
    • 指挥者(Director):这个角色负责按照特定的顺序调用具体建造者的方法来构建产品。指挥者知道如何组织和协调各个部件的构建过程,以确保按照正确的顺序完成。

3. 代码示例

3.1 示例1
  • 建造者模式代码示例
/**
 * 产品类
 */
class Product {
    private String partA;
    private String partB;

    public void setPartA(String partA) {
        this.partA = partA;
    }

    public void setPartB(String partB) {
        this.partB = partB;
    }

    public void show() {
        System.out.println("Product: " + partA + ", " + partB);
    }
}

/**
 * 抽象建造者
 */
abstract class Builder {
    protected Product product = new Product();

    public abstract void buildPartA();
    public abstract void buildPartB();
    public abstract Product getResult();
}

/**
 * 具体建造者
 */
class ConcreteBuilder extends Builder {
    @Override
    public void buildPartA() {
        product.setPartA("PartA");
    }

    @Override
    public void buildPartB() {
        product.setPartB("PartB");
    }

    @Override
    public Product getResult() {
        return product;
    }
}

// 指挥者
class Director {
    private Builder builder;

    public Director(Builder builder) {
        this.builder = builder;
    }

    public Product construct() {
        builder.buildPartA();
        builder.buildPartB();
        return builder.getResult();
    }
}

/**
 * 客户端代码
 */
public class Client {
    public static void main(String[] args) {
        Builder builder = new ConcreteBuilder();
        Director director = new Director(builder);
        Product product = director.construct();
        product.show();
    }
}

3.2 示例二
  • 实例代码
class MilkTea {
    double price;
    String topping = "cream";
    String tea = "Common tea";
    Integer suger = 100;

    public MilkTea() {
        this.price = 9.9;
    }

    public double getPrice() {
        return this.price;
    }
}

class LatteMilkTea extends MilkTea {
    public LatteMilkTea() {
        this.price = 10.9;
    }
}

class IceCreamMilkTea extends MilkTea {
    public IceCreamMilkTea() {
        this.price = 11.9;
    }
}

interface MilkteaBuilder {
    void reset();

    void addTopping();

    void addTea();

    void addSugerLevel();

    MilkTea getProduct();
}

class LatteMilkTeaBuilder implements MilkteaBuilder {

    private LatteMilkTea latteMilkTea;

    @Override
    public void reset() {
        this.latteMilkTea = new LatteMilkTea();
    }

    @Override
    public void addTopping() {
        latteMilkTea.topping = "latte topping";
    }

    @Override
    public void addTea() {
        latteMilkTea.tea = "latte tea";
    }

    @Override
    public void addSugerLevel() {
        latteMilkTea.suger = 95;
    }

    @Override
    public MilkTea getProduct() {
        System.out.format("LatteMilkTea: %s %s %s\n", this.latteMilkTea.topping, this.latteMilkTea.tea, this.latteMilkTea.price);
        return this.latteMilkTea;
    }
}

class IceCreamMilkTeaBuilder implements MilkteaBuilder {

    private IceCreamMilkTea iceCreamMilkTea;

    @Override
    public void reset() {
        this.iceCreamMilkTea = new IceCreamMilkTea();
    }

    @Override
    public void addTopping() {
        iceCreamMilkTea.topping = "ice cream topping";
    }

    @Override
    public void addTea() {
        iceCreamMilkTea.tea = "ice cream tea";
    }

    @Override
    public void addSugerLevel() {
        iceCreamMilkTea.suger = 95;
    }

    @Override
    public MilkTea getProduct() {
        System.out.format("LatteMilkTea: %s %s %s\n", this.iceCreamMilkTea.topping, this.iceCreamMilkTea.tea, this.iceCreamMilkTea.price);
        return this.iceCreamMilkTea;
    }
}

class MilkTeaDirector {
    private MilkteaBuilder milkteaBuilder;

    public MilkTeaDirector(MilkteaBuilder milkteaBuilder) {
        this.milkteaBuilder = milkteaBuilder;
    }

    public void changeBuiler(MilkteaBuilder milkteaBuilder) {
        this.milkteaBuilder = milkteaBuilder;
    }

    public MilkTea makeMikeTea() {
        this.milkteaBuilder.reset();
        this.milkteaBuilder.addTopping();
        this.milkteaBuilder.addTea();
        this.milkteaBuilder.addSugerLevel();
        return this.milkteaBuilder.getProduct();
    }

    public MilkTea make(String type) {
        if ("Latte".equals(type)) {
            this.changeBuiler(new LatteMilkTeaBuilder());
        } else if ("IceCream".equals(type)) {
            this.changeBuiler(new IceCreamMilkTeaBuilder());
        }
        return this.makeMikeTea();
    }

}

public class MilkTeaShop {
    public static void main(String[] args) {
        MilkTeaDirector director = new MilkTeaDirector(new LatteMilkTeaBuilder());
        director.makeMikeTea();
        director.changeBuiler(new IceCreamMilkTeaBuilder());
        director.makeMikeTea();
        director.make("Latte");
        director.make("IceCream");
    }
}


4. 优缺点

  • 主要作用
    • 逐步创建复杂的对象
  • 优点
    • 封装性好:创建和使用分离,用户无需了解产品内部细节。
    • 扩展性好:由于建造类之间相互独立,在一定程度上实现了解耦,易于扩展和维护。
    • 创建复杂对象:能够创建由各种复杂部件组成的产品,对于构造过程复杂的对象尤为有用。
  • 缺点
    • 增加类数量:可能会产生多余的Builder对象,增加系统的复杂度。
    • 修改困难:当产品内部发生变化时,可能需要相应地修改建造者,维护成本较高。

5. 应用场景

  • 对象构造复杂:当一个对象有很多属性,且这些属性的设置和组合非常复杂时,可以使用建造者模式来简化对象的构建过程。
  • 参数过多:如果一个类的构造函数参数超过四个,特别是当某些参数是可选的或有默认值时,建造者模式可以帮助避免构造函数过于臃肿。
  • 分步创建:在需要分步骤创建复杂对象时,建造者模式可以将每一步创建过程封装在不同的方法中,使得创建过程更加清晰和灵活。
  • 创建与使用分离:当希望将复杂对象的创建过程和使用过程分开时,建造者模式可以很好地实现这一目标,提高代码的可维护性和扩展性。
  • 多种表示:如果同一个复杂对象有多种不同的表示或配置方式,建造者模式可以通过不同的构建过程来创建这些不同的表示。
  • 顺序敏感:当对象的构建过程中调用顺序不同可能导致不同的结果时,建造者模式可以通过指导者(Director)来控制构建顺序,确保对象的正确构建。

6. JDK中的使用

  • StringBuilder类:这是JDK中一个典型的建造者模式实现。通过连续调用append方法,我们可以链式地构建一个字符串对象。最终,通过调用toString方法,我们可以得到一个完整的字符串对象。
  • MyBatis中的SqlSessionFactoryBuilder:MyBatis是一个广泛使用的持久层框架,它的SqlSessionFactoryBuilder类也使用了建造者模式。这个类提供了一种逐步配置并最终构建SqlSessionFactory对象的方法。

7. 建造者 VS 抽象工厂

建造者 抽象工厂
目的 构建复杂对象 创建一系列相关关联的对象
创建对象方式 多步骤创建 单一步骤创建

8. 注意事项

  • 明确需求:在实现建造者模式之前,需要明确复杂对象的构建需求。
  • 分清角色:清晰区分建造者、具体建造者、指挥者和产品的角色。
  • 构建解耦:确保构建过程与产品表示分离,使得同样的构建过程可以创建不同的表示。
  • 顺序重要:当产品的构建顺序很重要时,需要确保指挥者能够控制具体的构建步骤和顺序。
  • 避免过度设计:如果产品内部变化不复杂,不需要定义过多的具体建造者。

相关推荐

  1. 设计模式——建造模式

    2024-04-08 07:08:02       63 阅读
  2. 设计模式-建造模式

    2024-04-08 07:08:02       55 阅读
  3. 设计模式-建造模式

    2024-04-08 07:08:02       48 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-08 07:08:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-08 07:08:02       100 阅读
  3. 在Django里面运行非项目文件

    2024-04-08 07:08:02       82 阅读
  4. Python语言-面向对象

    2024-04-08 07:08:02       91 阅读

热门阅读

  1. redis和ElasticSearch和MongoDB应用场景,如何选择

    2024-04-08 07:08:02       32 阅读
  2. Docker 入门

    2024-04-08 07:08:02       28 阅读
  3. Git(8)之分支间同步特定提交

    2024-04-08 07:08:02       31 阅读
  4. 【Linux】在 Linux 上模拟网络故障

    2024-04-08 07:08:02       30 阅读
  5. Prompt提示词——常见的Prompt框架

    2024-04-08 07:08:02       31 阅读
  6. EXCEL学习笔记

    2024-04-08 07:08:02       39 阅读
  7. Mybatis学习笔记:多表关联,懒加载,缓存

    2024-04-08 07:08:02       33 阅读
  8. C语言正则表达式 regnext regreplace regreplaceAll

    2024-04-08 07:08:02       31 阅读
  9. uniapp使用vuex

    2024-04-08 07:08:02       37 阅读
  10. 一点点安全资料:数通知识扩展

    2024-04-08 07:08:02       35 阅读