家鄉(xiāng)的口味,西式的標(biāo)準(zhǔn)
自從和四大煉丹術(shù)士在爪媧山一別之后,御鳳獨自一人來到了亞美利加。由于吃膩了左宗棠雞,李鴻章雜碎,她覺得自己應(yīng)該做點什么,自己的那十幾口煉丹爐平時閑著也沒別的用,不如做飯吧。說干就干,你有肯德基,我有瑪薩基。御鳳用煉丹掙來的閑錢,在家門口開了一家中式快餐店,名字就叫瑪薩基。<br />
瑪薩基用餐流程簡明,效率高超。瑪薩基的廚房有主食、湯、自選菜、水果、飲料五大區(qū)域,根據(jù)用戶的選擇,通過自動傳送帶,構(gòu)建出成品套餐以供用戶享用。主食有米飯、白粥、爛糊面可選,湯有冬瓜排骨湯、羅宋湯、滋補牛鞭湯等選擇,其余不再贅述。瑪薩基提供兩種套餐:標(biāo)準(zhǔn)套餐和商務(wù)套餐,其中標(biāo)準(zhǔn)套餐由主食、湯、自選菜組成,不含水果飲料,商務(wù)套餐五種都包含。<br />
標(biāo)準(zhǔn)套餐 | 商務(wù)套餐 | |
---|---|---|
主食 | √ | √ |
湯 | √ | √ |
自選菜 | √ | √ |
水果 | × | √ |
飲品 | × | √ |
御鳳見招拆招,用了Builder模式來對付她的瑪薩基套餐這個復(fù)雜的Product,第一版代碼如下
Client.class
public class Client {
public static void main(String[] args) {
瑪薩基套餐Builder builder = new 標(biāo)準(zhǔn)套餐Builder();
Director director1 = new Director(builder);
菜[] dishes1 = {new 海蜇皮(), new 白斬雞()};
菜[] dishes2 = {new 紅燒羊肉(), new 白斬雞()};
director1.construct標(biāo)準(zhǔn)套餐(new 爛糊面(), dishes1, new 羅宋湯());
System.out.println(builder.create().toString());
瑪薩基套餐Builder 商務(wù)套餐Builder = new 商務(wù)套餐Builder();
Director director2 = new Director(商務(wù)套餐Builder);
director2.construct商務(wù)套餐(new 米飯(), dishes2, new 牛鞭湯(), new 紹興黃酒(), new 香蕉());
商務(wù)套餐Builder businessBuilder = (商務(wù)套餐Builder) 商務(wù)套餐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標(biāo)準(zhǔn)套餐(主食 stapleFood, 菜[] dishes, 湯 soup) {
builder.build主食(stapleFood);
builder.build自選菜(dishes);
builder.build湯(soup);
}
public void construct商務(wù)套餐(主食 stapleFood, 菜[] dishes, 湯 soup, 飲料 beverage, 水果 fruit) {
builder.build主食(stapleFood);
builder.build自選菜(dishes);
builder.build湯(soup);
商務(wù)套餐Builder businessBuilder = (商務(wù)套餐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();
}
}
商務(wù)套餐.class
public class 商務(wù)套餐 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();
}
標(biāo)準(zhǔn)套餐Builder.class
public class 標(biāo)準(zhǔn)套餐Builder extends 瑪薩基套餐Builder {
private 瑪薩基套餐 massage = new 標(biāo)準(zhǔn)套餐();
@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;
}
}
商務(wù)套餐Builder.class
public class 商務(wù)套餐Builder extends 瑪薩基套餐Builder {
private 商務(wù)套餐 massage = new 商務(wù)套餐();
@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;
}
}
運行結(jié)果
Builder模式和Abstract Factory的區(qū)別
Builder | Abstract Factory |
---|---|
一步步構(gòu)建一個復(fù)雜的product對象 | 著重于一組product對象的創(chuàng)建 |
最后一步返回product | 立即返回product |
簡單Builder模式在Java中的運用
結(jié)構(gòu)圖
- Client類
- 創(chuàng)建Builder和Director對象
- 將Builder的引用傳遞給Director
- 通過Director的構(gòu)造函數(shù)傳入
Director director = new Director(xBuilder);
- 通過Director的方法傳入
director.setBuilder(xBuilder);
- 通過Director的構(gòu)造函數(shù)傳入
- 通過Director的construct方法調(diào)用Builder的各個buildPart方法,完成Product的構(gòu)建
- Product類
- 如果Product種類比較多
- Product作為抽象類,具體的產(chǎn)品繼承該父類
- new Product()放在具體產(chǎn)品的Builder中
private Product product = new ConcreteProductA();
- 抽象Builder類提供一個getProduct()方法,在具體的Builder返回具體的Product引用
- Director的唯一功能就是調(diào)用Builder,將各個Part構(gòu)建起來
- 如果只有一種Product
- Product可以是一個具體類
- new Product()放在抽象Builder中,并對外提供一個createProduct()方法
- 在Director的construct方法中調(diào)用Builder的createProduct()方法
- 在Director中提供一個getProduct()方法,返回具體Product引用
總結(jié)
- Builder Pattern作為創(chuàng)建型模式,其著眼點在于Product,一切都是圍繞這個Product的創(chuàng)建而展開的
- Product由于整體較為復(fù)雜,將其拆分成若干Part,Builder負(fù)責(zé)將每個部分build好
- 靜態(tài)層面Variable,Product類有許多成員變量需要設(shè)置值,用Builder模式來替代使用多參數(shù)的構(gòu)造函數(shù)
- 動態(tài)層面Method,Product可以拆分成若干步驟,每一步又有其不同的具體實現(xiàn)方法(參見GOF-P75)
- 抽象Builder提供一個方法,用來給Client類通過Builder來得到最后生成的Product對象
- Builder模式可以精簡實現(xiàn),參見Android的AlertDialog
參考資料
Sourcemaking
Design Patterns in Java Tutorial
Wiki:Builder pattern