设计模式第10讲——建造者模式(Builder)

一、什么是建造者模式

建造者模式是一种创建型设计模式,也叫生成器模式

定义:封装一个复杂对象构造过程,并允许按步骤构造。

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

二、角色组成

  1. 产品类(Product):表示被创建的复杂对象。它通常包含多个部分或者组成,并由具体的建造者逐步构建而成。

  2. 抽象建造者类(Builder):定义了建造复杂对象所需要的各个部分的创建方法。它通常包括多个构建方法和一个返回产品的方法。

  3. 具体建造者类(ConcreteBuilder):实现Builder接口,并提供各个部分或者组成的构建方法。

  4. 指挥者类(Director):负责控制建造者的构建顺序,指挥建造者如何构建复杂对象。

三、优缺点

优点:

  1. 灵活:可以分步骤地构建复杂对象,使得构建过程更加灵活。
  2. 解耦:可以隔离复杂对象的创建和使用,客户端不必关心对象的创建细节。
  3. 易扩展:增加新的具体建造者很方便,可以扩展构建器功能,符合开闭原则。

缺点:

  1. 增加工作量:需要额外的代码来创建和管理具体建造者类,增加了程序员的工作量。
  2. 效率低:相比于其他创建型模式,在运行时效率较低,特别是对象太复杂时。

四、应用场景

4.1 生活场景

  • 盒饭套餐:顾客可以选择不同的菜,服务员按照顾客的要求,将这些菜组合起来,最终构建出一个完整的套餐。
  • 盖房子:需要分多个阶段进行,比如准备材料、打地基、盖围墙...。建造者模式可以将房屋的建造分解成多个步骤,每个步骤对应一个具体的建造者,最终由包工头(指导者)来调用不同的建造者,完成整个房子的建造。

4.2 java场景

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

五、代码实现

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

  1. 产品类:Meal

  2. 抽象建造者类:MealBuilder

  3. 具体建造者类:BeefBurgerMealBuilder、ChickenMealBuilder、ShrimpMealBuilder

  4. 指挥者类:MealDirector

5.0 UML类图

设计模式第10讲——建造者模式(Builder)_第1张图片

5.1 产品类(Product)

/**
 * @author Created by njy on 2023/6/12
 * 1.产品类(Product)
 */
@Data
public class Meal {

    //汉堡包
    private String burger;

    //薯条
    private String fries;

    //饮料
    private String drink;
}

5.2 抽象建造者(Builder)

/**
 * @author Created by njy on 2023/6/12
 * 2.抽象建造者(Builder)
 */
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;
    }
}

5.3 具体构建者(ConcreteBuilder)

/**
 * @author Created by njy on 2023/6/12
 * 3.具体建造者(ConcreteBuilder):鸡肉汉堡套餐
 */
public class ChickenMealBuilder extends MealBuilder{
    @Override
    public void buildBurger() {
        meal.setBurger("鸡肉汉堡");
    }

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

    @Override
    public void buildDrink() {
        meal.setDrink("大杯果汁");
    }
}
/**
 * @author Created by njy on 2023/6/12
 * 3.具体建造者(ConcreteBuilder):牛肉汉堡套餐
 */
public class BeefBurgerMealBuilder extends MealBuilder {

    @Override
    public void buildBurger() {
        meal.setBurger("牛肉汉堡");
    }

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

    @Override
    public void buildDrink() {
        meal.setDrink("中杯可乐");
    }
}
/**
 * @author Created by njy on 2023/6/12
 * 3.具体建造者(ConcreteBuilder):虾肉汉堡套餐
 */
public class ShrimpMealBuilder extends MealBuilder {
    @Override
    public void buildBurger() {
        meal.setBurger("虾肉汉堡");
    }

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

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

5.4 指导者(Director)

/**
 * @author Created by njy on 2023/6/12
 * 4.指导者(Director)
 */
public class MealDiretor {
    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();
    }
}

5.5 testBuilder

/**
 * @author Created by njy on 2023/6/12
 * 建造者模式测试类
 */
@SpringBootTest
public class TestBuilder {

    @Test
    void testBuilder(){
        //创建指导者
        MealDiretor diretor=new MealDiretor();

        //执导建造牛肉套餐
        diretor.setMealBuilder(new BeefBurgerMealBuilder());
        diretor.constructMeal();
        Meal meal = diretor.getMeal();
        System.out.println("牛肉套餐:"+meal.toString());

        //鸡肉套餐
        diretor.setMealBuilder(new ChickenMealBuilder());
        diretor.constructMeal();
        Meal meal2 = diretor.getMeal();
        System.out.println("鸡肉套餐:"+meal2.toString());

        //虾肉套餐
        diretor.setMealBuilder(new ShrimpMealBuilder());
        diretor.constructMeal();
        Meal meal3 = diretor.getMeal();
        System.out.println("虾肉套餐:"+meal3.toString());
    }
}

设计模式第10讲——建造者模式(Builder)_第2张图片

可以看到,根据不同的需求,建造者模式可以构造出不同的套餐对象。每个套餐的构建过程都由不同的建造者实现,在构建过程中可定制相应的属性。最终,因为套餐的构建过程和表示分离,所以同样的构建过程可以创建出不同的表示。

六、总结

使用场景:

  1. 当需要创建一些特定的对象,但是它们拥有共同的组成部分时,比如:一个房子可以由个个部件:框架、墙、窗户等,这些部件可以组合起来构造完整的房子。
  2. 当对象的构建过程比较复杂且需要多个步骤时,例如,创建一份电子商务订单需要多个步骤,如选择商品、填写地址和支付等,这些步骤可以被分别封装成为订单构建器中的不同方法。
  3. 当需要创建一些特定类型的对象,例如复杂的数据结构或配置对象时,这在编写配置文件解析器以及通用数据结构如二叉树等时很有用。
  4. 建造者模式也可以被用于通过更高级的方式来构建复杂对象,例如:序列化和反序列化。

与抽象工厂模式的区别:

        抽象工厂模式强调的是产品族的创建,即相关的产品一起被创建出来,而建造者模式强调的是一个复杂对象的创建,即它的各个部分逐步被创建出来。

END:更多设计模式的介绍,推荐移步至 23种设计模式学习导航(Java完整版)

你可能感兴趣的:(设计模式,设计模式,建造者模式,java,面试)