设计模式之建造者模式

245 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情

简介

当我们需要实列化一个复杂的类,以得到不同结构类型和不同的内部状态的对象时,我们可以用不同的类对它们的实列化操作逻辑分别进行封装,这些类我们就称之为建造者。当我们需要来之同一个类,但是要就有不同结构对象时,就可以通过构造另一个建造者来进行实列化。

在建造者模式中,我们通常会定义以下4种角色的类:

  • Proudct 即上述所说的复杂的产品类,我们要创建它的对象
  • Builder 抽象的建造者,定义实例化产品类的所需要执行的方法
  • ConcreteBuilder 具体的建造类,继承抽象的建造者,定义具体的产品的创建方法
  • Director 导演类,可理解为我们客户端

案例

如果有使用过Lombok的同学看到这里应该会想起来Lombok有一个注解@Builder,就是使用了建造者模式,使用这个注解使我们构造一个对象变得很方便,而且链式编程,可以节省很多代码。不用先new出来,然后通过set方法一个个属性取set,如下:

@Builder
public class Food {
    private String name;
    private String cost;
    public static void main(String[] args) {
        Food.builder().name("西红柿鸡蛋").cost("23").build();
    }
}

但是Lombok只是建造者模式思想的一个简单体现,下面咱们来实现一个。

比如日常生活种厨师做菜,菜品种类很多,但是他们的属性却是大致固定的,比如菜品的名称、价格、颜色、味道等属性,那我们要如何构造这些不同的菜品呢?

首先定义菜品类,包含名称、价格、颜色和味道属性

public class Food {
    private String name;
    private Integer cost;
    private String taste;
    private String color;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getCost() {
        return cost;
    }
    public void setCost(Integer cost) {
        this.cost = cost;
    }
    public String getTaste() {
        return taste;
    }
    public void setTaste(String taste) {
        this.taste = taste;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    @Override
    public String toString() {
        return "Food{" +
                "name='" + name + ''' +
                ", cost=" + cost +
                ", taste='" + taste + ''' +
                ", color='" + color + ''' +
                '}';
    }
}

然后咱们需要定义一个抽象的建造者:

public abstract class Builder {
    abstract Builder name(String name);
    abstract Builder color(String cost);
    abstract Builder cost(Integer cost);
    abstract Builder taste(String taste);
    abstract Food build();
}

接下来需要定义一个做菜的厨师了,厨师通过实现建造者抽象类来给菜品生成属性:

public class Cooker extends Builder {
    private Food food;
    public Cooker() {
        this.food = new Food();
    }
    @Override
    Builder name(String name) {
        food.setName(name);
        return this;
    }
    @Override
    Builder color(String color) {
        food.setColor(color);
        return this;
    }
    @Override
    Builder cost(Integer cost) {
        food.setCost(cost);
        return this;
    }
    @Override
    Builder taste(String taste) {
        food.setTaste(taste);
        return this;
    }
    Food build() {
        return this.food;
    }
}

最后就是咱们的客户或者服务员,这里可以理解为一个点菜的过程。通过链式的编程定义了一个菜品的名称、颜色、价格与味道,当然我们点菜的时候可以任意指定某个属性为某个值,或者不指定某属性的值都可以。

public class App {
    public static void main(String[] args) {
        Food food = new Cooker()
                .name("鱼香肉丝")
                .color("红色")
                .cost(23)
                .taste("辣").build();
        System.out.println(food);
    }
}

总结

通过以上实战和理解,我们可以看出来建造者模式

  • 产品的建造和表示分离开来,实现功能解耦,如此可以使客户端不需要知道产品内部的组成细节,只关注需要的部分。
  • 将复杂对象的实例化分解在不同的方法种,通过链式编程使初始化变得更加简介与方便。
  • 具体的建造者(Cooker)是独立的,只要菜品不变,我们可以对建造者进行拓展(这个厨师做菜的顺序和方式不合胃口),新增的建造者满足开闭原则。