创建型模式->建造者模式

创建型模式->建造者模式(Builder)

什么是建造者模式

建造者模式是一种创建型设计模式,也叫生成器模式。
定义:封装一个复杂对象构造过程,并允许按步骤构造。

解释:就是将复杂对象的创建过程拆分成多个简单对象的创建过程,并将这些简单对象组合起来构建出复杂对象。

角色组成

产品类(Product): 表示被创建的复杂对象。它通常包含多个部分或者组成,并由具体的建造者逐步构建而成。
抽象建造者类(Builder): 定义了建造复杂对象所需要的各个部分的创建方法。它通常包括多个构建方法和一个返回产品的方法。
具体建造者类(ConcreteBuilder): 实现Builder接口,并提供各个部分或者组成的构建方法。
指挥者类(Director): 负责控制建造者的构建顺序,指挥建造者如何构建复杂对象。

优缺点

优点:

  1. 灵活:可以分步骤地构建复杂对象,使得构建过程更加灵活。

  2. 解耦:可以隔离复杂对象的创建和使用,客户端不必关心对象的创建细节。

  3. 易扩展:增加新的具体建造者很方便,可以扩展构建器功能,符合开闭原则。
    缺点:

  4. 增加工作量:需要额外的代码来创建和管理具体建造者类,增加了程序员的工作量。

  5. 效率低:相比于其他创建型模式,在运行时效率较低,特别是对象太复杂时。

应用场景

生活场景

  • 盒饭套餐:顾客可以选择不同的菜,服务员按照顾客的要求,将这些菜组合起来,最终构建出一个完整的套餐。

Java场景

StringBuilder: 能够动态地构建字符串。
Stream API: 将集合类转为stream流,通过一系列的中间操作和终止操作来生成最终结果。
Lombok的@Builder注解: 一个注解就可以生成建造者模式的代码

代码实现

肯德徳都吃过吧,里面有很多的套餐。假设套餐主要由汉堡、薯条和饮料三种组成,每个组件都有不同种类和大小,并且每个套餐的组合方式也不同。下面以肯德徳套餐为例,解释建造者模式。

产品类: Meal
抽象建造者类: MealBuilder
具体建造者类: BeefBurgerMealBuilder、ChickenMealBuilder、ShrimpMealBuilder
指挥者类: MealDirector

套餐类 (Meal)

java 复制代码
/**
 * @author cris
 * @className Meal
 * @description 套餐产品类
 * @date 2024/06/29 08:11
 **/
@Getter
@Setter
@ToString
public class Meal {
    /**
     * 汉堡
     */
    private String burger;

    /**
     * 薯条
     */
    private String fries;

    /**
     * 饮料
     */
    private String drink;
}

抽象建造者(Builder)

java 复制代码
/**
 * @author cris
 * @className MealBuilder
 * @description 抽象建造者
 * @date 2024/06/29 08:13
 **/
public abstract class MealBuilder {
    protected Meal meal = new Meal();

    /**
     * 构建汉堡
     */
    public abstract void buildBurger();

    /**
     * 构建薯条
     */
    public abstract void buildFries();

    /**
     * 构建饮料
     */
    public abstract void buildDrink();

    public Meal getMeal() {
        return meal;
    }

}

具体构建者 (ConcreteBuilder)

java 复制代码
/**
 * @author cris
 * @className ChickenMealBuilder
 * @description 具体建造者(ConcreteBuilder):鸡肉汉堡套餐
 * @date 2024/06/29 08:16
 **/
public class ChickenMealBuilder extends MealBuilder {
    @Override
    public void buildBurger() {
        meal.setBurger("鸡肉汉堡");
    }

    @Override
    public void buildFries() {
        meal.setFries("中份薯条");
    }

    @Override
    public void buildDrink() {
        meal.setDrink("大杯果汁");
    }
}
java 复制代码
/**
 * @author cris
 * @className BeefMealBuilder
 * @description 具体建造者(ConcreteBuilder):牛肉汉堡套餐
 * @date 2024/06/29 08:18
 **/
public class BeefMealBuilder extends MealBuilder {
    @Override
    public void buildBurger() {
        meal.setBurger("牛肉汉堡");
    }

    @Override
    public void buildFries() {
        meal.setFries("大份薯条");
    }

    @Override
    public void buildDrink() {
        meal.setDrink("大杯可乐");
    }
}
java 复制代码
/**
 * @author cris
 * @className ShrimpMealBuilder
 * @description 具体建造者(ConcreteBuilder):虾肉汉堡套餐
 * @date 2024/06/29 08:19
 **/
public class ShrimpMealBuilder extends MealBuilder {
    @Override
    public void buildBurger() {
        meal.setBurger("虾肉汉堡");
    }

    @Override
    public void buildFries() {
        meal.setFries("小份薯条");
    }

    @Override
    public void buildDrink() {
        meal.setDrink("大杯芬达");
    }
}

指导者 (Director)

java 复制代码
/**
 * @author cris
 * @className MealDirector
 * @description 指导者(Director)
 * @date 2024/06/29 08:21
 **/
public class MealDirector {

    private MealBuilder mealBuilder;

    public void setMealBuilder(MealBuilder mealBuilder) {
        this.mealBuilder = mealBuilder;
    }

    public Meal getMeal() {
        return mealBuilder.getMeal();
    }

    // 制作套餐
    public void constructMeal() {
        mealBuilder.buildBurger();
        mealBuilder.buildFries();
        mealBuilder.buildDrink();
    }
}

测试 (TestBuilder)

java 复制代码
/**
 * @author cris
 * @className TestBuilder
 * @description 测试
 * @date 2024/06/29 08:25
 **/
public class TestBuilder {

    public static void main(String[] args) {
        MealDirector mealDirector = new MealDirector();

        mealDirector.setMealBuilder(new ChickenMealBuilder());
        mealDirector.constructMeal();
        Meal meal1 = mealDirector.getMeal();
        System.out.println("鸡肉汉堡套餐" + meal1.toString());

        mealDirector.setMealBuilder(new BeefMealBuilder());
        mealDirector.constructMeal();
        Meal meal2 = mealDirector.getMeal();
        System.out.println("牛肉汉堡套餐" + meal2.toString());

        mealDirector.setMealBuilder(new ShrimpMealBuilder());
        mealDirector.constructMeal();
        Meal meal3 = mealDirector.getMeal();
        System.out.println("虾肉汉堡套餐" + meal3.toString());
    }
}

总结

使用场景:

  1. 当需要创建一些特定的对象,但是它们拥有共同的组成部分时,比如:一个房子可以由个个部件:框架、墙、窗户等,这些部件可以组合起来构造完整的房子。
  2. 当对象的构建过程比较复杂且需要多个步骤时,例如,创建一份电子商务订单需要多个步骤,如选择商品、填写地址和支付等,这些步骤可以被分别封装成为订单构建器中的不同方法。
  3. 当需要创建一些特定类型的对象,例如复杂的数据结构或配置对象时,这在编写配置文件解析器以及通用数据结构如二叉树等时很有用。
  4. 建造者模式也可以被用于通过更高级的方式来构建复杂对象,例如:序列化和反序列化。
    与抽象工厂模式的区别:
  • 抽象工厂模式强调的是产品族的创建,即相关的产品一起被创建出来,而建造者模式强调的是一个复杂对象的创建,即它的各个部分逐步被创建出来。
相关推荐
brzhang8 分钟前
别再梭哈 Curosr 了!这 AI 神器直接把需求、架构、任务一条龙全干了!
前端·后端·架构
安妮的心动录22 分钟前
安妮的2025 Q2 Review
后端·程序员
程序员爱钓鱼23 分钟前
Go语言数组排序(冒泡排序法)—— 用最直观的方式掌握排序算法
后端·google·go
Victor3561 小时前
MySQL(140)如何解决外键约束冲突?
后端
Victor3561 小时前
MySQL(139)如何处理MySQL字符编码问题?
后端
007php0073 小时前
服务器上PHP环境安装与更新版本和扩展(安装PHP、Nginx、Redis、Swoole和OPcache)
运维·服务器·后端·nginx·golang·测试用例·php
武子康5 小时前
Java-72 深入浅出 RPC Dubbo 上手 生产者模块详解
java·spring boot·分布式·后端·rpc·dubbo·nio
椰椰椰耶7 小时前
【Spring】拦截器详解
java·后端·spring
brzhang8 小时前
我操,终于有人把 AI 大佬们 PUA 程序员的套路给讲明白了!
前端·后端·架构