標籤:android模板方法模式
在閻宏博士的《JAVA與模式》一書中開頭是這樣描述模板方法(Template Method)模式的:
模板方法模式是類的行為模式。準備一個抽象類別,將部分邏輯以具體方法以及具體建構函式的形式實現,然後聲明一些抽象方法來迫使子類實現剩餘的邏輯。不同的子類可以以不同的方式實現這些抽象方法,從而對剩餘的邏輯有不同的實現。這就是模板方法模式的用意。
模板方法模式的結構
模板方法模式是所有模式中最為常見的幾個模式之一,是基於繼承的代碼複用的基本技術。
模板方法模式需要開發抽象類別和具體子類的設計師之間的協作。一個設計師負責給出一個演算法的輪廓和骨架,另一些設計師則負責給出這個演算法的各個邏輯步驟。代表這些具體邏輯步驟的方法稱做基本方法(primitive method);而將這些基本方法匯總起來的方法叫做模板方法(template method),這個設計模式的名字就是從此而來。
模板方法所代表的行為稱為頂級行為,其邏輯稱為頂級邏輯。模板方法模式的靜態結構圖表如下所示,以Android View為例:
這裡涉及到兩個角色:
抽象模板(Abstract Template)角色(其實不一定要是抽象類別,如本例的View)有如下責任:
■ 定義了一個或多個抽象操作,以便讓子類實現。這些抽象操作叫做基本操作,它們是一個頂級邏輯的組成步驟。
■ 定義並實現了一個模板方法。這個模板方法一般是一個具體方法,它給出了一個頂級邏輯的骨架,而邏輯的組成步驟在相應的抽象操作中,延遲到子類實現。頂級邏輯也有可能調用一些具體方法。
具體模板(Concrete Template)角色有如下責任:
■ 實現父類所定義的一個或多個抽象方法,它們是一個頂級邏輯的組成步驟。
■ 每一個抽象模板角色都可以有任意多個具體模板角色與之對應,而每一個具體模板角色都可以給出這些抽象方法(也就是頂級邏輯的組成步驟)的不同實現,從而使得頂級邏輯的實現各不相同。
模板模式的關鍵是:子類可以置換掉父類的可變部分,但是子類卻不可以改變模板方法所代表的頂級邏輯。
每當定義一個新的子類時,不要按照控制流程程的思路去想,而應當按照“責任”的思路去想。換言之,應當考慮哪些操作是必須置換掉的,哪些操作是可以置換掉的,以及哪些操作是不可以置換掉的。使用模板模式可以使這些責任變得清晰。
模板方法模式中的方法
模板方法中的方法可以分為兩大類:模板方法和基本方法。
模板方法
一個模板方法是定義在抽象類別中的,把基本操作方法組合在一起形成一個總演算法或一個總行為的方法。
一個抽象類別可以有任意多個模板方法,而不限於一個。每一個模板方法都可以調用任意多個具體方法。
基本方法
基本方法又可以分為三種:抽象方法(Abstract Method)、具體方法(Concrete Method)和鉤子方法(Hook Method)。
● 抽象方法:一個抽象方法由抽象類別聲明,由具體子類實現。在Java語言裡抽象方法以abstract關鍵字標示。
● 具體方法:一個具體方法由抽象類別聲明並實現,而子類並不實現或置換。
● 鉤子方法:一個鉤子方法由抽象類別聲明並實現,而子類會加以擴充。通常抽象類別給出的實現是一個空實現,作為方法的預設實現。
預設鉤子方法
一個鉤子方法常常由抽象類別給出一個空實現作為此方法的預設實現。這種空的鉤子方法叫做“Do Nothing Hook”。顯然,這種預設鉤子方法在預設適配模式裡面已經見過了,一個預設適配模式講的是一個類為一個介面提供一個預設的空實現,從而使得預設適配類的子類不必像實現介面那樣必須給出所有方法的實現,因為通常一個具體類並不需要所有的方法。(文字來源於網路,轉載)
原始碼:
public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {...... /** * Implement this to do your drawing. * * @param canvas the canvas on which the background will be drawn */ protected void onDraw(Canvas canvas) { }...... /** * Manually render this view (and all of its children) to the given Canvas. * The view must have already done a full layout before this function is * called. When implementing a view, implement * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. * If you do need to override this method, call the superclass version. * * @param canvas The Canvas to which the View is rendered. */ public void draw(Canvas canvas) { ...... onDraw(canvas); ...... dispatchDraw(canvas); ...... onDrawScrollBars(canvas); ...... }...... /** * <p>Request the drawing of the horizontal and the vertical scrollbar. The * scrollbars are painted only if they have been awakened first.</p> * * @param canvas the canvas on which to draw the scrollbars * * @see #awakenScrollBars(int) */ protected final void onDrawScrollBars(Canvas canvas) { ...... }...... /** * Called by draw to draw the child views. This may be overridden * by derived classes to gain control just before its children are drawn * (but after its own view has been drawn). * @param canvas the canvas on which to draw the view */ protected void dispatchDraw(Canvas canvas) { }......}
public class TextView extends View implements ViewTreeObserver.OnPreDrawListener { @Override protected void onDraw(Canvas canvas) { ...... //TextView的具體畫法。。。 super.onDraw(canvas); ...... }}
Android與設計模式——模板方法(Template Method)模式