家乡的口味,西式的标准
自从和四大炼丹术士在爪娲山一别之后,御凤独自一人来到了亚美利加。由于吃腻了左宗棠鸡,李鸿章杂碎,她觉得自己应该做点什么,自己的那十几口炼丹炉平时闲着也没别的用,不如做饭吧。说干就干,你有肯德基,我有玛萨基。御凤用炼丹挣来的闲钱,在家门口开了一家中式快餐店,名字就叫玛萨基。
玛萨基用餐流程简明,效率高超。玛萨基的厨房有主食、汤、自选菜、水果、饮料五大区域,根据用户的选择,通过自动传送带,构建出成品套餐以供用户享用。主食有米饭、白粥、烂糊面可选,汤有冬瓜排骨汤、罗宋汤、滋补牛鞭汤等选择,其余不再赘述。玛萨基提供两种套餐:标准套餐和商务套餐,其中标准套餐由主食、汤、自选菜组成,不含水果饮料,商务套餐五种都包含。
标准套餐 | 商务套餐 | |
---|---|---|
主食 | √ | √ |
汤 | √ | √ |
自选菜 | √ | √ |
水果 | × | √ |
饮品 | × | √ |
御凤见招拆招,用了Builder模式来对付她的玛萨基套餐这个复杂的Product,第一版代码如下
Client.class
public class Client {
public static void main(String[] args) {
玛萨基套餐Builder builder = new 标准套餐Builder();
Director director1 = new Director(builder);
菜[] dishes1 = {new 海蜇皮(), new 白斩鸡()};
菜[] dishes2 = {new 红烧羊肉(), new 白斩鸡()};
director1.construct标准套餐(new 烂糊面(), dishes1, new 罗宋汤());
System.out.println(builder.create().toString());
玛萨基套餐Builder 商务套餐Builder = new 商务套餐Builder();
Director director2 = new Director(商务套餐Builder);
director2.construct商务套餐(new 米饭(), dishes2, new 牛鞭汤(), new 绍兴黄酒(), new 香蕉());
商务套餐Builder businessBuilder = (商务套餐Builder) 商务套餐Builder;
System.out.println(businessBuilder.create().toString());
}
}
Director.class
public class Director {
玛萨基套餐Builder builder = null;
public Director(玛萨基套餐Builder builder) {
this.builder = builder;
}
public void construct标准套餐(主食 stapleFood, 菜[] dishes, 汤 soup) {
builder.build主食(stapleFood);
builder.build自选菜(dishes);
builder.build汤(soup);
}
public void construct商务套餐(主食 stapleFood, 菜[] dishes, 汤 soup, 饮料 beverage, 水果 fruit) {
builder.build主食(stapleFood);
builder.build自选菜(dishes);
builder.build汤(soup);
商务套餐Builder businessBuilder = (商务套餐Builder) builder;
businessBuilder.build饮料(beverage);
businessBuilder.build水果(fruit);
}
}
玛萨基套餐.class
public abstract class 玛萨基套餐 {
protected 主食 stapleFood;
protected 菜[] dishes;
protected 汤 soup;
public 玛萨基套餐() {
}
public void setStapleFood(主食 stapleFood) {
this.stapleFood = stapleFood;
}
public void setDishes(菜[] dishes) {
this.dishes = dishes;
}
public void setSoup(汤 soup) {
this.soup = soup;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder()
.append("主食是:").append(stapleFood.getClass().getSimpleName())
.append(", 菜有丰盛的");
for (菜 dish : dishes) {
sb.append(dish.getClass().getSimpleName() + ",");
}
sb.append(" 汤是上好的").append(soup.getClass().getSimpleName()).toString();
return sb.toString();
}
}
商务套餐.class
public class 商务套餐 extends 玛萨基套餐 {
protected 水果 fruit;
protected 饮料 beverage;
public void setFruit(水果 fruit) {
this.fruit = fruit;
}
public void setBeverage(饮料 beverage) {
this.beverage = beverage;
}
@Override
public String toString() {
return super.toString() +
", 水果是" + fruit.getClass().getSimpleName() +
", 饮料是" + beverage.getClass().getSimpleName();
}
}
玛萨基套餐Builder.class
public abstract class 玛萨基套餐Builder {
public abstract void build汤(汤 soup);
public abstract void build主食(主食 stapleFood);
public abstract void build自选菜(菜[] dishes);
public abstract 玛萨基套餐 create();
}
标准套餐Builder.class
public class 标准套餐Builder extends 玛萨基套餐Builder {
private 玛萨基套餐 massage = new 标准套餐();
@Override
public void build汤(汤 soup) {
massage.setSoup(soup);
}
@Override
public void build主食(主食 stapleFood) {
massage.setStapleFood(stapleFood);
}
@Override
public void build自选菜(菜[] dishes) {
massage.setDishes(dishes);
}
@Override
public 玛萨基套餐 create() {
return massage;
}
}
商务套餐Builder.class
public class 商务套餐Builder extends 玛萨基套餐Builder {
private 商务套餐 massage = new 商务套餐();
@Override
public void build汤(汤 soup) {
massage.setSoup(soup);
}
@Override
public void build主食(主食 stapleFood) {
massage.setStapleFood(stapleFood);
}
@Override
public void build自选菜(菜[] dishes) {
massage.setDishes(dishes);
}
public void build饮料(饮料 beverage) {
massage.setBeverage(beverage);
}
public void build水果(水果 fruit) {
massage.setFruit(fruit);
}
@Override
public 玛萨基套餐 create() {
return massage;
}
}
运行结果
Builder模式和Abstract Factory的区别
Builder | Abstract Factory |
---|---|
一步步构建一个复杂的product对象 | 着重于一组product对象的创建 |
最后一步返回product | 立即返回product |
简单Builder模式在Java中的运用
结构图
- Client类
- 创建Builder和Director对象
- 将Builder的引用传递给Director
- 通过Director的构造函数传入
Director director = new Director(xBuilder);
- 通过Director的方法传入
director.setBuilder(xBuilder);
- 通过Director的构造函数传入
- 通过Director的construct方法调用Builder的各个buildPart方法,完成Product的构建
- Product类
- 如果Product种类比较多
- Product作为抽象类,具体的产品继承该父类
- new Product()放在具体产品的Builder中
private Product product = new ConcreteProductA();
- 抽象Builder类提供一个getProduct()方法,在具体的Builder返回具体的Product引用
- Director的唯一功能就是调用Builder,将各个Part构建起来
- 如果只有一种Product
- Product可以是一个具体类
- new Product()放在抽象Builder中,并对外提供一个createProduct()方法
- 在Director的construct方法中调用Builder的createProduct()方法
- 在Director中提供一个getProduct()方法,返回具体Product引用
总结
- Builder Pattern作为创建型模式,其着眼点在于Product,一切都是围绕这个Product的创建而展开的
- Product由于整体较为复杂,将其拆分成若干Part,Builder负责将每个部分build好
- 静态层面Variable,Product类有许多成员变量需要设置值,用Builder模式来替代使用多参数的构造函数
- 动态层面Method,Product可以拆分成若干步骤,每一步又有其不同的具体实现方法(参见GOF-P75)
- 抽象Builder提供一个方法,用来给Client类通过Builder来得到最后生成的Product对象
- Builder模式可以精简实现,参见Android的AlertDialog
参考资料
Sourcemaking
Design Patterns in Java Tutorial
Wiki:Builder pattern