樣板, 顧名思義就是把同樣的邏輯定義成一個樣板, 可讓其他類別共同使用
樣板也會開放可客製化的方法 (抽象方法), 供其他類別實作
樣板主要核心
- 將共同演算法邏輯包裝好
- 定義非共同的方法為抽像方法, 請使用樣板方法的類別自行實作
透過泡茶與泡咖啡來瞭解樣板模式吧
這時候若直接寫code, 會分別定義出 Tea
與 Coffee
class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| class Tea { Tea() {}
public void prepare() { System.out.println("=======開始準備茶的動作======="); boilWater(); steepTeaBag(); addLenmon(); pourIntoCup(); System.out.println("=======結束======="); }
private void boilWater() { System.out.println("燒開水"); }
private void steepTeaBag() { System.out.println("泡開茶包"); }
private void addLenmon() { System.out.println("加入檸檬"); }
private void pourIntoCup() { System.out.println("倒入杯中"); } }
class Coffee { Coffee() {}
public void prepare() { System.out.println("=======開始準備咖啡的動作======="); boilWater(); greedCoffeeGrinds(); addCreamer(); pourIntoCup(); System.out.println("=======結束======="); }
private void boilWater() { System.out.println("燒開水"); }
private void greedCoffeeGrinds() { System.out.println("磨咖啡豆"); }
private void addCreamer() { System.out.println("加奶精"); }
private void pourIntoCup() { System.out.println("倒入杯中"); } }
|
使用以上定義的方法
1 2 3 4 5 6 7 8 9
| public class main { public static void main(String[] args) { Tea tea = new Tea(); tea.prepare();
Coffee coffee = new Coffee(); coffee.prepare(); } }
|
套用Template Pattern吧
仔細比較泡茶和泡咖啡, 都會有著以下類似的動作
- 煮沸開水
- 將(茶的茶包/咖啡藥磨成粉)泡開 <-- 這個動作一樣, 但茶是用茶包, 咖啡是需要先磨成粉
- 添加有的沒的 (咖啡會用奶精/茶會放檸檬) <-- 這邊的也是一樣
- 倒進杯中
剛好茶與咖啡都是含有咖啡因的飲料,這時就可以定義一個樣板叫做 CaffeineBeverage
, 並把上述 2,3步驟,定義成抽象方法, 讓茶與咖啡類別自己去實作自己的邏輯
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| abstract class CaffeineBeverage { String name = "咖啡因飲料"; CaffeineBeverage(String name) { this.name = name; }
public void prepare() { System.out.println("=======開始準備 " + this.name + " 的動作======="); boilWater(); brew(); addCondiments(); pourIntoCup(); System.out.println("=======結束======="); }
private void boilWater() { System.out.println("燒開水"); }
abstract void brew(); abstract void addCondiments();
private void pourIntoCup() { System.out.println("倒進杯中"); } }
|
接著Tea
與Coffee
實現該樣板類別 CaffeineBeverage
並根據自己的邏輯實作abstract方法 brew()
與addCondiments()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| class Tea extends CaffeineBeverage { Tea(String name) { super(name); }
public void prepare() { System.out.println("=======開始準備茶的動作======="); boilWater(); brew(); addCondiments(); pourIntoCup(); System.out.println("=======結束======="); }
@Override void brew() { System.out.println("泡開茶包"); }
@Override void addCondiments() { System.out.println("加入檸檬"); } }
class Coffee extends CaffeineBeverage{ Coffee(String name) { super(name); }
public void prepare() { System.out.println("=======開始準備咖啡的動作======="); boilWater(); brew(); addCondiments(); pourIntoCup(); System.out.println("=======結束======="); }
@Override void brew() { System.out.println("磨咖啡豆"); }
@Override void addCondiments() { System.out.println("加奶精"); } }
|
接著一樣使用之
1 2 3 4 5 6 7 8 9
| public class main { public static void main(String[] args) { CaffeineBeverage tea = new Tea("茶"); tea.prepare();
CaffeineBeverage coffee = new Coffee("咖啡"); coffee.prepare(); } }
|
小結
透過以上方法可以看到 樣板模式 將重複的地方給統整起來成為演算法邏輯, 並定義一個抽象類別, 將需要客製化的部分定義成抽象方法, 統一的部分就直接定義實體方法
如此一來各個類別在實作時,就不用在自己去做重複一樣的動作(例如燒開水, 倒入杯中) 只要直接繼承樣板抽象類別就有囉, 然後在自己實作自己需要的部分 (如茶有自己的茶包泡法, 咖啡則有自己的咖啡豆要磨 才能泡)
以實現樣板模式的精神
透過hook方法將封裝的演算法邏輯部分做控制使用
待補充