携手创作,共同成长!这是我参与「掘金日新计划 · 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)是独立的,只要菜品不变,我们可以对建造者进行拓展(这个厨师做菜的顺序和方式不合胃口),新增的建造者满足开闭原则。