第十篇:模板方法模式

我們先來談談 "模板" 的概念,什麼是模板? 很簡單嘛,直接上圖!



這就是一個模板!它定義了基本的樣式,整個文檔結構,內容大綱,而你要做的,就是再某些地方寫上自己的內容就可以了! 讓我們用代碼來舉一個模板方法的例子吧!

我們擬定一個炒米粉的過程(因爲我今天吃的是米粉),首先,要刷鍋,然後放油,放入粉條,翻炒, 放鹽,接下來可以選擇放醋,放辣椒,放蔥, 然後起鍋放入碗中, 自此整個流程完畢!

我們來分析一下這個過程:


通過畫圖,我們發現,其中某些步驟是完全固定的,那我們就可以思考,是不是可以有一個類,然後定義一個總的方法,這個方法就像是一個大的算法(把炒米粉看成是一個算法吧)骨架,或者說它就是一個模板,在這個方法中,它順序調用不同的方法(步驟) , 先調用刷鍋(),再放油()...接下來要解決放粉條的問題,怎麼辦,它自己不知道要放什麼粉條,OK,抽象嘛,讓子類來決定要放什麼粉條咯!  再接下來要放醋...到底放不放呢? 放醋的過程是固定的,我們要複用這段代碼,那怎麼辦呢? 那具體放醋過程還是我們父類自己覺得,而到底要不要放我們則可以問一下子類嘛!當它回答說不放,那就不放!

Ok,思路已經很清晰了!我們來讓代碼說話吧!

先來幾個面和粉的對象...

/**所有粉條父類*/
public abstract class Flour {
	protected String name ;

	public String getName() {return name;}
	public void setName(String name) {this.name = name;}
}

/**掛麪*/
class NoodlesFlour extends Flour{
	public NoodlesFlour() {
		this.name = "掛麪";
	}
}
/**米粉*/
class RiceFlour extends Flour{
	public RiceFlour() {
		this.name = "米粉";
	}
}

 接下來定義我們的模板類!

/**定義一個炒粉抽象模板方法類*/
abstract class AbstractFryFlourTemplate{
	
	//定義爲final,因爲算法過程(炒粉過程)是固定的!我希望算法過程不被子類覆蓋!
	public final void startFry(){
		rinse();
		addOil();
		addFlour();
		roll();
		addSalt();
		
		//仔細看看,這部分像不像是一個鉤子?
		if( isAddVinegar() ){
			addVinegar();
		}
		if( isAddPepper() ){
			addPepper();
		}
		
		addToBowl();
	}
	
	private final void rinse(){
		System.out.println("刷鍋...");
	}
	private final void addOil(){
		System.out.println("放點油...");
	}
	//抽象方法,放入米粉
	protected abstract void addFlour();
	
	//翻炒方法,子類可以根據炒法不同而進行覆蓋
	protected void roll(){
		System.out.println("默認慢慢的炒...");
	}
	private final void addSalt(){
		System.out.println("放點鹽...");
	}
	
	//放醋方法
	private final void addVinegar(){
		System.out.println("打開醋瓶");
		System.out.println("放點醋...");
		System.out.println("關好醋瓶");
	} 
	
	//放辣椒方法
	private final void addPepper(){
		System.out.println("放點辣椒!");
	} 
	
	private final void addToBowl(){
		System.out.println("放到碗裏去...");
	}
	
	//到底放不放醋,子類可以來做決定,但我們默認放!
	protected boolean isAddVinegar(){
		return true;
	}
	
	//到底放不放辣椒,必須子類做出決定,也就是必須問下客戶,您要辣椒不?
	protected abstract boolean isAddPepper();
}

再定義兩個不同的算法類...

/**炒麪的類*/
class FlyNoodlesFlour extends AbstractFryFlourTemplate{
	@Override
	protected void addFlour() {
		Flour flour = new NoodlesFlour();
		System.out.println("放入:"+flour.getName());
	}

	//客人說要放辣椒
	@Override
	protected boolean isAddPepper() {
		return true;
	}
	//覆蓋翻炒方法,我是高級廚師...
	@Override
	protected void roll() {
		System.out.println("各種花樣百出的炒...");
	}
}

/**炒粉的類*/
class FlyRiceFlour extends AbstractFryFlourTemplate{
	@Override
	protected void addFlour() {
		Flour flour = new RiceFlour();
		System.out.println("放入:"+flour.getName());
	}

	//客人說不要放辣椒
	@Override
	protected boolean isAddPepper() {
		return false;
	}
	
	//客人還說也不要放醋
	@Override
	protected boolean isAddVinegar() {
		return false;
	}
}

測試一下:

public class Test {
	
	public static void main(String[] args) {
		AbstractFryFlourTemplate aft = new FlyNoodlesFlour();
		aft.startFry();
		
		System.out.println("*****************************");
		AbstractFryFlourTemplate aft2 = new FlyRiceFlour();
		aft2.startFry();
	}
}

輸出:*******************************************************************

刷鍋...
放點油...
放入:掛麪
各種花樣百出的炒...
放點鹽...
打開醋瓶
放點醋...
關好醋瓶
放點辣椒!
放到碗裏去...
*****************************
刷鍋...
放點油...
放入:米粉
默認慢慢的炒...
放點鹽...
放到碗裏去...

**************************************************************************


Ok,我們來分析一下上面的代碼吧!AbstractFryFlourTemplate類定義了一個統一的炒麪粉的模板,可以把它看做事一個算法骨架,一個框架;  我們看到,它完成一個算法的流程是固定的,但某些流程它無法自己完成,所以定義爲抽象的,讓子類去完成, 更有趣的是,它定義了兩個鉤子方法,鉤子方法有默認值,也就是這個算法默認就會這麼去做,當然它也允許子類去決定到底要不要這樣做,比如要不要放醋; 這一點,我們可以說成是, 通過定義鉤子方法,模板類可以讓子類參與和改變算法的某些執行過程!


最後,我們來定義一下模板方法: 在一個方法中定義一個算法的骨架,但它允許將某些執行內容延遲到子類去執行; 通過鉤子方法,它允許子類改變算法的執行過程!





發佈了48 篇原創文章 · 獲贊 5 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章