一.什麼是模版方法模式?html
首先,模版方法模式是用來封裝算法骨架的,也就是算法流程java
既然被稱爲模版,那麼它確定容許擴展類套用這個模版,爲了應對變化,那麼它也必定容許擴展類作一些改變算法
事實就是這樣,模版方法模式封裝了算法流程,但容許由子類負責實現某些步驟細節ide
二.舉個例子測試
假設咱們要開一家容許加盟的炸醬麪店,咱們擁有獨家祕製的醬料配方,以及獨特的製做工藝,美味只此一家,地球上大多數人天天都吃咱們的炸醬麪,因此咱們有了大量的加盟者this
爲了盈利,咱們固然不能公開製做工藝與醬料配方,但因爲加盟者經營地域的差別,製做細節又存在差別,好比北京人喜歡吃細面硬麪,陝西人喜歡吃寬面軟面,咱們也不能爲了保護配方而讓北京的加盟者繼續賣咱們的寬面spa
因此咱們須要把製做工藝與保密配方保護起來,誰都不容許修改,同時把麪條的製做以及烹煮方式公開出去,容許加盟者修改htm
那麼,要如何實現這樣的需求?對象
沒錯,模版方法就是爲此而生的blog
-------
首先,咱們須要創建模版類,把該保護的保護起來,把該公開的公開出去:
package TemplateMethodPattern; /** * @author ayqy * 定義炸醬麪模版類 */ public abstract class Noodles { public void cook(){ //製做麪條 makeNoodles(); //製做醬料 makeSauce(); //烹煮麪條 boilNoodles(); //添加醬料 addSauce(); } /** * 把祕製醬料保護起來 */ private void makeSauce(){ System.out.println("作好一份獨家祕製醬料"); } /** * 把添加劑量保護起來 */ private void addSauce(){ System.out.println("添加適量的祕製醬料"); } public abstract void makeNoodles(); public abstract void boilNoodles(); }
定義好了模版,90%的工做就已經完成了,下面開始實現具體類
北京炸醬麪:
package TemplateMethodPattern; /** * @author ayqy * 實現北京炸醬麪具體類 */ public class BJNoodles extends Noodles{ @Override public void makeNoodles() { System.out.println("作好一份有北京特點的手工面"); } @Override public void boilNoodles() { System.out.println("按北京特點煮麪法煮好麪條"); } }
陝西炸醬麪:
package TemplateMethodPattern; /** * @author ayqy * 實現陝西炸醬麪具體類 */ public class SXNoodles extends Noodles{ @Override public void makeNoodles() { System.out.println("作好一份有陝西特點的手工面"); } @Override public void boilNoodles() { System.out.println("按陝西特點煮麪法煮好麪條"); } }
有了這些具體類,咱們按照地域分配給加盟者就行了
三.效果示例
先實現一個測試類:
package TemplateMethodPattern; /** * @author ayqy * 實現一個測試類 */ public class Test { public static void main(String[] args){ //建立北京炸醬麪對象 Noodles bjnoodles = new BJNoodles(); //建立陝西炸醬麪對象 Noodles sxnoodles = new SXNoodles(); System.out.println("北京炸醬麪製做工藝:"); bjnoodles.cook();//作一份北京炸醬麪 System.out.println("\n陝西炸醬麪製做工藝:"); sxnoodles.cook();//作一份陝西炸醬麪 } }
運行結果:
四.多一點思考
上面的例子中,咱們很輕鬆的實現了對算法骨架的封裝,並且容許擴展類自定義某些步驟細節,彷佛很輕鬆也很完美
那好,讓咱們改改需求吧:
最近提倡綠色健康生活,你們都喜歡吃點蔬菜,咱們傳統的炸醬麪不得不與時俱進,作好以後還要添點蔬菜
但問題是有的地方並不喜歡添加蔬菜,他們習慣了老字號炸醬麪的風味,堅定不要蔬菜
因此咱們不能簡單地改變製做工藝,添加一道工序來加蔬菜
-------
若是能在模版中定義一個可選的操做就再好不過了,讓加盟者本身選擇要不要加點兒蔬菜
因而,咱們須要對以前的模版作一點點改動:
package TemplateMethodPattern; /** * @author ayqy * 定義炸醬麪模版類 */ public abstract class Noodles { private boolean wantVegetables = false;//要不要蔬菜 public void setWantVegetables(boolean wantVegetables) { this.wantVegetables = wantVegetables; } public void cook(){ //製做麪條 makeNoodles(); //製做醬料 makeSauce(); //烹煮麪條 boilNoodles(); //要不要添點兒蔬菜 if(wantVegetables) addVegetables(); //添加醬料 addSauce(); } /** * 把祕製醬料保護起來 */ private void makeSauce(){ System.out.println("作好一份獨家祕製醬料"); } /** * 把添加劑量保護起來 */ private void addSauce(){ System.out.println("添加適量的祕製醬料"); } /** * 添加時令蔬菜 */ public void addVegetables(){ //空的實現 } public abstract void makeNoodles(); public abstract void boilNoodles(); }
注意,爲了添加可選的操做,咱們作了這麼幾件事情:
五.模版方法模式與策略模式
這兩個模式都是用來封裝算法的,讓咱們來對比一下:
策略模式 | 模版方法模式 | |
概念 | 封裝算法步驟,容許子類選擇已有的策略(步驟細節) | 封裝算法骨架(流程),容許由子類負責實現某些細節 |
實現方式 | 用組合來實現 | 用繼承來實現 |
目標 | 實現了算法步驟的選擇 | 實現了算法的流程控制 |
亮點 | 支持運行時動態改變步驟(策略) | 支持運行時動態改變算法流程(用hook來實現) |
具體步驟 | 把易於變化的同類算法細節(步驟)找出來,再定義一個算法族(接口)把它們封裝起來 | 把算法骨架抽象出來並封裝在基類(模版類)中 |
總結 | 封裝步驟 | 封裝流程 |
舉個例子:
假設如今有一個算法,流程是A->B->C->D,C步驟的具體實現可能有c1,c2,c3三種不一樣方法
策略模式:
模版方法模式: