分析設計模式之模板方法Java實現(xiàn)
從字面意義上理解, 模板方法就是定義出來一套方法, 作為模板, 也就是基礎。 在這個基礎上, 我們可以進行加工,實現(xiàn)個性化的實現(xiàn)。比如:一日餐三. 早餐, 中餐, 晚餐. 每個人都要吃三餐, 但每個人的三餐吃的可能都不一樣. 一日三餐定義了模板--早中晚, 每個人的三餐就是模板的具體實現(xiàn).
1.1、模板方法的用途 將不變的行為從子類搬到超類,去除了子類中的重復代碼 規(guī)范子類的結構1.2、模板方法的定義定義一個操作中的算法骨架,而將算法的一些步驟延遲到子類中,使得子類可以不改變該算法結構的情況下重定義該算法的某些特定步驟。它是一種類行為型模式。
二、定義模板方法的步驟2.1、定義模板類通常模板類是抽象類,負責給出算法的輪廓或者框架。他是有若干個模板方法和若干個基本方法構成。
1.模板方法
定義了算法的骨架, 定義了方法調用的順序, 其中包含一個或者多個基本方法
2.基本方法
基本算法有三種類型:
a) 抽象方法:子類必須重寫的方法。沒有默認實現(xiàn)。
b)具體方法:父類定義的默認實現(xiàn),有實現(xiàn)邏輯,可以被具體的子類繼承或重寫
c)鉤子方法:判斷的邏輯方法和需要子類重寫的空方法兩種。
2.2、定義具體子類具體子類,也就是具體的實現(xiàn)類, 實現(xiàn)抽象類中的抽象方法。他們是抽象的模板方法中一個組成部分。
2.3、定義客戶端調用客戶端調用抽象類, 實例化的時候實例化具體類, 只需要調用抽象類的模板方法就可以了。
2.4 下抽象類和子類之間的UML圖和源碼實現(xiàn)1.UML圖
從圖中可以看出抽象類的結構可以定義三類方法。 可以有一個也可以有多個。子類必須需要實現(xiàn)抽象類中的抽象方法,可以選擇性重寫父類的具體方法。子類實現(xiàn)接口的時候,要多思考設計模式的六大原則。
2.源碼
先定義抽象類, 也就是框架。
package com.lxl.www.designPatterns.templatePattern.template;/** * 抽象類, 定義模板 */public abstract class AbstractClass { /** * 定義模板方法 * 規(guī)范了流程的框架 */ public void templateMethod() {// 先調用具體方法specificMethod();// 在調用抽象方法abstractMethod(); } /** * 具體方法 */ public void specificMethod() {// 具體的公共邏輯, 父子類通用System.out.println('具體方法---父子類通用邏輯'); } /** * 抽象方法 * * 抽象方法, 子類必須重寫 */ public abstract void abstractMethod();}
在定義具體的實現(xiàn)類, 實現(xiàn)父類的抽象方法
package com.lxl.www.designPatterns.templatePattern.template;/** * 具體實現(xiàn)類 */public class ConcreteClass extends AbstractClass{ /** * 重寫父類的抽象方法 */ @Override public void abstractMethod() {System.out.println('具體實現(xiàn)類--重寫父類的抽象方法'); }}
最后定義客戶端調用
package com.lxl.www.designPatterns.templatePattern.template;/** * 模板方法客戶端 */public class TemplateClient { public static void main(String[] args) {AbstractClass abstractClass = new ConcreteClass();abstractClass.templateMethod(); }}
運行結果:
具體方法---父子類通用邏輯
具體實現(xiàn)類--重寫父類的抽象方法
對照模板方法設計模式,我們來看一個具體的案例。
三、案例3.1、案例1: 一日規(guī)劃每個人的一日安排都有三餐, 早餐, 中餐,晚參。 但每個人的三餐食物不盡相同,我們來看看每個人的三餐變化, 以及三餐前后要做的事情。
package com.lxl.www.designPatterns.templatePattern.oneDayArrangement;/** * 一日三餐抽象類 */public abstract class ArrangementAbstract { /** * 模板方法 * 規(guī)定了一天的框架 */ public void templateMethod() {System.out.println('一日安排如下: ');getUp();breakfast();lunch();dinner();getDown(); } public void getUp() {System.out.println('起床'); } public void getDown() {System.out.println('睡覺'); } /** * 早餐抽象類 */ public abstract void breakfast() ; /** * 午餐抽象類 */ public abstract void lunch(); /** * 晚餐抽象類 */ public abstract void dinner();}
定義一日三餐抽象類。每個人的日程安排都是,起床,早餐,中餐,晚餐,睡覺。 其中起床和睡覺是每個人都要做的事情,三餐也是,但三餐的食物不同,于是我們將三餐定義為抽象
一日安排實現(xiàn)類
package com.lxl.www.designPatterns.templatePattern.oneDayArrangement;/** * 張三的一日三餐安排 */public class PersonArrangement extends ArrangementAbstract{ private String name; public PersonArrangement(String name) {this.name = name; } /** * 早餐抽象類 */ public void breakfast(){System.out.println(name + '--早餐吃牛奶面包'); } /** * 午餐抽象類 */ public void lunch() {System.out.println(name + '--中餐吃食堂'); } /** * 晚餐抽象類 */ public void dinner() {System.out.println(name + '--晚餐吃水果'); }}
客戶端調用
public class Client { public static void main(String[] args) {ArrangementAbstract zhangsan = new PersonArrangement('張三');zhangsan.templateMethod(); }}
運行結果:
一日安排如下:起床張三--早餐吃牛奶面包張三--中餐吃食堂張三--晚餐吃水果睡覺
可以看出, 完全按照模板方法的步驟實現(xiàn)。
3.2、案例2: 鉤子方法我們上面說了, 模板方法設計模式中, 基本方法包括抽象方法,具體方法和鉤子方法.如果能夠使用好鉤子方法, 可以在程序中完美實現(xiàn)子類控制父類的行為. 我們來看下面的案例:
我們在抽象方法中定義一個鉤子方法hookMethod(), 在模板方法templateMethod()中,鉤子方法控制了代碼的流程.
UML圖:
源代碼:
package com.lxl.www.designPatterns.templatePattern.hookMethod;/** * 抽象類, 定義模板 */public abstract class AbstractClass { /** * 定義模板方法 * 規(guī)范了流程的框架 */ public void templateMethod() {// 調用具體方法specificMethod();// 鉤子方法控制下一步驟if (hookMethod()) { // 調用抽象方法 abstractMethod();} } /** * 具體方法 */ public void specificMethod() {// 具體的公共邏輯, 父子類通用System.out.println('具體方法---父子類通用邏輯'); } /** * 鉤子方法 * 鉤子方法是有具體實現(xiàn)的, */ public boolean hookMethod() {return true; } /** * 抽象方法 * * 抽象方法, 子類必須重寫 */ public abstract void abstractMethod();}
定義具體實現(xiàn)
/** * 具體實現(xiàn)類 */public class ConcreteClass extends AbstractClass { /** * 重寫父類的抽象方法 */ @Override public void abstractMethod() {System.out.println('具體實現(xiàn)類--重寫父類的抽象方法'); } /** * 鉤子方法 * @return */ @Override public boolean hookMethod() {System.out.println('重寫了父類的鉤子方法, 反向控制父類的行為');return false; }}
重寫了鉤子方法, 反向控制父類的行為
public class TemplateClient { public static void main(String[] args) {AbstractClass abstractClass = new ConcreteClass();abstractClass.templateMethod(); }}
運行結果
具體方法---父子類通用邏輯重寫了父類的鉤子方法, 反向控制父類的行為
如果子類鉤子方法 HookMethod() 的代碼改變,則程序的運行結果也會發(fā)生改變。
四、模板方法的優(yōu)缺點4.1、優(yōu)點1.規(guī)范了框架, 封裝了不變的部分, 擴展了可變的部分. 父類定義框架, 并抽象了公共不變的部分, 子類通過重寫擴展完善了框架的實現(xiàn)。
2.使用了'開閉原則', 對擴展開放, 對修改關閉. 子類可以通過重寫父類的抽象方法來擴展父類的實現(xiàn)。
3.行為集中有父類控制, 規(guī)范流程。
4.2、缺點1.每一種實現(xiàn)都需要定義一個具體實現(xiàn)類, 增加類的數(shù)量, 系統(tǒng)更加復雜。
2.繼承的缺點, 一旦父類增加一個抽象方法, 所有子類都需要增加. 這一點違背'開閉原則'。
3.父類中的抽象方法由子類實現(xiàn), 子類的執(zhí)行結果影響父類, 這種'反向控制'結構, 會增加代碼的復雜性。
五、使用場景1.算法的整體步驟是固定的,但個別部分容易發(fā)生變化時,可以考慮使用模板方法設計模式,將容易發(fā)生變化的部分抽象出來,提供給子類去實現(xiàn)。
2.當多個子類存在公共的行為時,可以將其提取出來并集中到一個公共父類中以避免代碼重復。首先,要識別現(xiàn)有代碼中的不同之處,并且將不同之處分離為新的操作。最后,用一個調用這些新的操作的模板方法來替換這些不同的代碼。
3.當需要控制子類的擴展時,模板方法只在特定點調用鉤子操作,這樣就只允許在這些點進行擴展。
4.重構時,模板方法模式是一個經(jīng)常使用到的模式,把相同的代碼抽取到父類中,通過鉤子函數(shù)約束其行為
六、對設計模式六大原則的應用思考1.單一職責原則: 一個方法只有一個引起變化的原因, 這個不太好看出, 要開子類代碼的具體實現(xiàn)
2.里式替換原則: 父類出現(xiàn)的地方都可以使用子類替換,并且結果保持一致. 子類重寫了父類的方法。 模板方法設計模式可能違背里式替換原則, 不過,這正是能夠“反向控制”的原理
3.接口隔離原則: 依賴于最小的單一接口, 而不是胖接口. 符合
4.依賴倒置原則: 依賴于抽象, 而不是依賴于具體. 符合
5.迪米特法則: 最少知識原則. 之和朋友溝通, 減少和朋友的溝通. 這個需要看子類具體實現(xiàn)是否符合
6.開閉原則: 違背開閉原則, 一旦父類增加一個抽象方法, 所有子類都需要對應增加
以上就是分析設計模式之模板方法的詳細內(nèi)容,更多關于設計模式 模板方法的資料請關注好吧啦網(wǎng)其它相關文章!
相關文章:
