設計模式之模版方法模式(Template Method Pattern)

一.什麼是模版方法模式?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();
}

注意,爲了添加可選的操做,咱們作了這麼幾件事情:

  1. 定義標誌變量(選/不選)
  2. 提供標誌變量的setter,供擴展類選擇
  3. 修改算法骨架,加入新的可選步驟
  4. 爲新的步驟提供一個空的實現(注意,這一步很重要,提供空的實現而不是定義一個抽象方法,避免了對現有擴展類的修改,這個在模版方法模式的術語中被稱爲Hook鉤子

五.模版方法模式與策略模式

這兩個模式都是用來封裝算法的,讓咱們來對比一下:

  策略模式 模版方法模式
概念 封裝算法步驟,容許子類選擇已有的策略(步驟細節) 封裝算法骨架(流程),容許由子類負責實現某些細節
實現方式 用組合來實現 用繼承來實現
目標 實現了算法步驟的選擇 實現了算法的流程控制
亮點 支持運行時動態改變步驟(策略) 支持運行時動態改變算法流程(用hook來實現)
具體步驟 把易於變化的同類算法細節(步驟)找出來,再定義一個算法族(接口)把它們封裝起來 把算法骨架抽象出來並封裝在基類(模版類)中
總結 封裝步驟 封裝流程

舉個例子:

假設如今有一個算法,流程是A->B->C->D,C步驟的具體實現可能有c1,c2,c3三種不一樣方法

策略模式:

  1. 定義一個行爲接口C,定義execute方法
  2. 實現具體類c1,c2,c3擴展自接口C(c1,c2,c3三種行爲供調用者選擇)
  3. 在基類中添加一個屬性,類型爲接口C,並提供setter
  4. 擴展自基類的具體類將經過調用setter來動態改變行爲

模版方法模式:

  1. 定義基類(模版類),在基類中定義算法流程(把流程封裝起來)
  2. 在基類中把C步驟定義爲抽象方法
  3. 擴展自基類的具體類將提供本身的實現(c1,c2,c3或者其它)
相關文章
相關標籤/搜索