What:
定義一個(gè)操作中的算法骨架栏妖,而將算法的一些步驟延遲到子類中灾炭,使得子類可以不改變該算法結(jié)構(gòu)的情況下重定義該算法的某些特定步驟返敬。
Why:
優(yōu)點(diǎn):
1.封裝不變部分挡闰,擴(kuò)展可變部分逗扒。
2.提取公共代碼古戴,便于維護(hù)。
3.行為由父類控制矩肩,子類實(shí)現(xiàn)现恼,符合開閉原則。
4.代碼復(fù)用黍檩,減少代碼冗余叉袍。
缺點(diǎn):
1.每一個(gè)不同的實(shí)現(xiàn)都需要增加子類,導(dǎo)致類數(shù)目增加刽酱,增加類系統(tǒng)的復(fù)雜度喳逛;
2.由于繼承的關(guān)系,父類增加或者修改抽象方法棵里,子類都需要修改润文。
Where:
1.多個(gè)類共有的方法姐呐,且邏輯相同。
2.一次性實(shí)現(xiàn)一個(gè)算法的不變部分转唉,并將可變的行為留給子類實(shí)現(xiàn)皮钠。
How:
模版模式的角色比較簡單,只有抽象父類和具體子類赠法。
AbstractClass(抽象父類): 定義模版方法麦轰,也就是定義一些公共的行為,將可變的行為抽象砖织,讓子類具體實(shí)現(xiàn)款侵。
ConcreteClass(具體子類): 實(shí)現(xiàn)抽象父類,具體實(shí)現(xiàn)可變的行為侧纯。
在寫具體代碼之前新锈,先了解一下鉤子方法。
鉤子方法是什么呢眶熬?
就是在抽象類中定義一個(gè)方法妹笆,默認(rèn)不做任何事,子類可以根據(jù)實(shí)際情況要不要覆蓋它娜氏,從而改變行為拳缠,該方法稱為“鉤子”。
示例:模擬制作咖啡店家接收訂單的過程贸弥。父類Coffee定義了共有的方法窟坐,如加熱水,研磨咖啡豆绵疲,同時(shí)也定義了可變部分哲鸳,有的消費(fèi)者不喜歡加奶加糖,所以定義了鉤子方法isAddMilkFlag和isAddSugarFlag判斷是否需要加奶和糖盔憨。而子類繼承抽象父類根據(jù)實(shí)際需要判斷是否需要添加奶和糖徙菠。
Coffee(抽象父類):
public abstract class Coffee {
boolean addSugarFlag = false;
boolean addMilkFlag = false;
public boolean isAddMilkFlag() {
return addMilkFlag;
}
public boolean isAddSugarFlag() {
return addSugarFlag;
}
Coffee prepareHotWater(){
System.out.println("準(zhǔn)備熱水");
return this;
}
Coffee grindCoffeeBean(){
System.out.println("研磨咖啡豆");
return this;
}
void addSugar(){
System.out.println("加糖");
}
void addMilk(){
System.out.println("加奶");
}
Coffee make(String coffeeName){
Coffee coffee = prepareHotWater().grindCoffeeBean();
if(isAddMilkFlag()){
coffee.addMilk();
}
if(isAddSugarFlag()){
coffee.addSugar();
}
System.out.println("制作完成!這是一杯"
+ (isAddSugarFlag() ? "加" : "不加") + "糖,"
+ (isAddMilkFlag() ? "加" : "不加") + "奶"
+ "的" + coffeeName);
return coffee;
}
}
Cappuccino類和Latte類:
public class Cappuccino extends Coffee {
String coffeeName = "卡布奇諾";
Coffee make(){
return super.make(this.coffeeName);
}
@Override
public boolean isAddSugarFlag() {
return true;
}
}
public class Latte extends Coffee {
String coffeeName = "拿鐵";
Coffee make(){
return super.make(this.coffeeName);
}
@Override
public boolean isAddMilkFlag() {
return true;
}
@Override
public boolean isAddSugarFlag() {
return true;
}
}
Test:測試類
public class Test {
public static void main(String[] args) {
System.out.println("****** 下訂單:一杯加糖,不加奶的熱卡布奇諾 ******");
Cappuccino cappuccino = new Cappuccino();
cappuccino.make();
System.out.println("****** 下訂單:一杯加糖,加奶的熱拿鐵 ******");
Latte latte = new Latte();
latte.make();
}
}
輸出結(jié)果:
****** 下訂單:一杯加糖,不加奶的熱卡布奇諾 ******
準(zhǔn)備熱水
研磨咖啡豆
加糖
制作完成郁岩!這是一杯加糖,不加奶的卡布奇諾
****** 下訂單:一杯加糖,加奶的熱拿鐵 ******
準(zhǔn)備熱水
研磨咖啡豆
加奶
加糖
制作完成懒豹!這是一杯加糖,加奶的拿鐵
總結(jié)
使用模版模式可以很方便的將共有的代碼提取出來,能降低代碼的冗余驯用,加快開發(fā)效率。在實(shí)際開發(fā)中也經(jīng)常用到模版模式的設(shè)計(jì)思想儒老。譬如前端html頁面蝴乔,頁頭和頁尾總是一樣的,那么可以創(chuàng)建頁頭(header.html)和頁尾(footer.html)模版驮樊,在每個(gè)html頁面都直接引用薇正,這樣的話片酝,既能夠節(jié)省時(shí)間,又能大大的減少代碼量挖腰。