摘要:模板方法模式定義定義抽象類并且聲明一些抽象基本方法供子類實(shí)現(xiàn)不同邏輯,同時(shí)在抽象類中定義具體方法把抽象基本方法封裝起來(lái),這就是模板方法模式。
近日,ofo小黃車宣布入駐法國(guó)巴黎,正式進(jìn)入全球第20個(gè)國(guó)家,共享單車已然改變了我們的出行方式。就拿我自己來(lái)說(shuō),每當(dāng)下班出地鐵的第一件事,以光速鎖定一輛共享單車,百米沖刺的速度搶在別人之前占領(lǐng)它。
而大家都是重復(fù)著同樣的動(dòng)作,拿出手機(jī)開(kāi)鎖、騎車、上鎖、結(jié)算,哇~這是何等壯觀的場(chǎng)景,甚至還有的不用開(kāi)鎖直接把車騎走的,鎖壞了嘛。
為什么要用模板方法模式
現(xiàn)在共享單車以開(kāi)鎖的方式來(lái)分,一般有掃碼開(kāi)鎖和密碼開(kāi)鎖兩種,來(lái)看共享單車使用流程的實(shí)現(xiàn)。
正常的思維邏輯是,抽象一個(gè)父類,子類繼承父類并實(shí)現(xiàn)父類方法。OK,看抽象類代碼:
public abstract class AbstractClass {
// 開(kāi)鎖 public abstract void unlock(); // 騎行 public abstract void ride(); // 上鎖 public abstract void lock(); // 結(jié)算 public abstract void pay(); // 用戶使用 public abstract void use();
}
抽象類定義了我們使用共享單車的幾個(gè)基本流程,現(xiàn)在有兩種不同開(kāi)鎖方式單車的使用,都繼承抽象類,代碼如下:
//
public class ScanBicycle extends AbstractClass {
@Override public void unlock() { System.out.println("掃碼開(kāi)鎖"); } @Override public void ride() { System.out.println("騎起來(lái)很拉風(fēng)"); } @Override public void lock() { System.out.println("上鎖"); } @Override public void pay() { System.out.println("結(jié)算"); } @Override public void use() { unlock(); ride(); lock(); pay(); }
}
以上是通過(guò)掃碼方式開(kāi)鎖騎行,再來(lái)看密碼開(kāi)鎖騎行,代碼如下:
public class CodeBicycle extends AbstractClass {
@Override public void unlock() { System.out.println("密碼開(kāi)鎖"); } @Override public void ride() { System.out.println("騎起來(lái)很拉風(fēng)"); } @Override public void lock() { System.out.println("上鎖"); } @Override public void pay() { System.out.println("結(jié)算"); } @Override public void use() { unlock(); ride(); lock(); pay(); }
}
好了,兩種方式都定義好了,看客戶端的調(diào)用:
public class Client {
public static void main(String[] args) { ScanBicycle scanBicycle = new ScanBicycle(); scanBicycle.use(); System.out.println("========================"); CodeBicycle codeBicycle = new CodeBicycle(); codeBicycle.use(); }
}
結(jié)果如下:
掃碼開(kāi)鎖
騎起來(lái)很拉風(fēng)
上鎖
掃碼開(kāi)鎖
騎起來(lái)很拉風(fēng)
上鎖
結(jié)算
相信都已經(jīng)看出代碼的問(wèn)題,use方法的實(shí)現(xiàn)是一樣的,也就是代碼重復(fù)了,這是病必須得治,藥方就是模板方式模式。
模板方法模式
定義
??定義抽象類并且聲明一些抽象基本方法供子類實(shí)現(xiàn)不同邏輯,同時(shí)在抽象類中定義具體方法把抽象基本方法封裝起來(lái),這就是模板方法模式。
UML
模板方法模式
模板方法模式涉及到的角色有兩個(gè)角色:
抽象模板角色:定義一組基本方法供子類實(shí)現(xiàn),定義并實(shí)現(xiàn)組合了基本方法的模板方法。
具體模板角色:實(shí)現(xiàn)抽象模板角色定義的基本方法
模板方法模式還涉及到以下方法的概念:
基本方法
抽象方法:由抽象模板角色聲明,abstract修飾,具體模板角色實(shí)現(xiàn)。
鉤子方法:由抽象模板角色聲明并實(shí)現(xiàn),具體模板角色可實(shí)現(xiàn)加以擴(kuò)展。
具體方法:由抽象模板角色聲明并實(shí)現(xiàn),而子類并不實(shí)現(xiàn)。
模板方法
抽象模板角色聲明并實(shí)現(xiàn),負(fù)責(zé)對(duì)基本方法的調(diào)度,一般以final修飾,不允許具體模板角色重寫(xiě)。模板方法一般也是一個(gè)具體方法。
模式實(shí)戰(zhàn)
利用模板方式模式對(duì)上面的代碼進(jìn)行重構(gòu),來(lái)看抽象模板角色,代碼如下:
public abstract class AbstractClass {
protected boolean isNeedUnlock = true; // 默認(rèn)需要開(kāi)鎖 /** * 基本方法,子類需要實(shí)現(xiàn) */ protected abstract void unlock(); /** * 基本方法,子類需要實(shí)現(xiàn) */ protected abstract void ride(); /** * 鉤子方法,子類可實(shí)現(xiàn) * * @param isNeedUnlock */ protected void isNeedUnlock(boolean isNeedUnlock) { this.isNeedUnlock = isNeedUnlock; } /** * 模板方法,負(fù)責(zé)調(diào)度基本方法,子類不可實(shí)現(xiàn) */ public final void use() { if (isNeedUnlock) { unlock(); } else { System.out.println("========鎖壞了,不用解鎖========"); } ride(); }
}
抽象模板角色定義了unlock和ride兩個(gè)使用單車的基本方法,還有一個(gè)鉤子方法,用來(lái)控制模板方法邏輯順序,核心是use模板方法,用final修飾,該方法完成對(duì)基本方法調(diào)度。注意,模板方法中對(duì)基本方法的調(diào)度是有順序有規(guī)則的。還有一點(diǎn),基本方法都是protected修飾的,因?yàn)榛痉椒ǘ际窃谝詐ublic修飾的模板方法中調(diào)用,并且可以由子類實(shí)現(xiàn),并不需要暴露給其他類調(diào)用。
現(xiàn)在來(lái)看兩個(gè)具體模板角色的實(shí)現(xiàn):
// 掃碼開(kāi)鎖的單車
public class ScanBicycle extends AbstractClass {
@Override protected void unlock() { System.out.println("========" + "掃碼開(kāi)鎖" + "========"); } @Override protected void ride() { System.out.println(getClass().getSimpleName() + "騎起來(lái)很拉風(fēng)"); } protected void isNeedUnlock(boolean isNeedUnlock) { this.isNeedUnlock = isNeedUnlock; }
}
// 密碼開(kāi)鎖的單車
public class CodeBicycle extends AbstractClass {
@Override protected void unlock() { System.out.println("========" + "密碼開(kāi)鎖" + "========"); } @Override protected void ride() { System.out.println(getClass().getSimpleName() + "騎起來(lái)很拉風(fēng)"); } protected void isNeedUnlock(boolean isNeedUnlock) { this.isNeedUnlock = isNeedUnlock; }
}
可以看到,相比之前的實(shí)現(xiàn),現(xiàn)在兩個(gè)具體類都不需要實(shí)現(xiàn)use方法,只負(fù)責(zé)實(shí)現(xiàn)基本方法的邏輯,職責(zé)上變得更加清晰了。來(lái)看用戶如何使用:
public class Client {
public static void main(String[] args) { ScanBicycle scanBicycle = new ScanBicycle(); scanBicycle.use(); CodeBicycle codeBicycle = new CodeBicycle(); codeBicycle.use(); }
}
運(yùn)行結(jié)果如下:
========掃碼開(kāi)鎖========
ScanBicycle騎起來(lái)很拉風(fēng)
========密碼開(kāi)鎖========
CodeBicycle騎起來(lái)很拉風(fēng)
當(dāng)我以百米沖刺的速度跑到共享單車面前時(shí),發(fā)現(xiàn)這輛車的鎖是壞掉的,也就是不用開(kāi)鎖,免費(fèi)的,騎回家收藏也沒(méi)問(wèn)題。在代碼中只要調(diào)用鉤子方法isNeedUnlock就好,實(shí)現(xiàn)如下:
public class Client {
public static void main(String[] args) { ScanBicycle scanBicycle = new ScanBicycle(); scanBicycle.isNeedUnlock(false); scanBicycle.use(); CodeBicycle codeBicycle = new CodeBicycle(); codeBicycle.isNeedUnlock(true); codeBicycle.use(); }
}
運(yùn)行結(jié)果如下:
========鎖壞了,不用解鎖========
ScanBicycle騎起來(lái)很拉風(fēng)
========密碼開(kāi)鎖========
CodeBicycle騎起來(lái)很拉風(fēng)
上面提到模板方法對(duì)基本方法的調(diào)度是有順序的,也就是說(shuō)模板方法中的邏輯是不可變的,子類只實(shí)現(xiàn)可以被實(shí)現(xiàn)的基本方法,但不會(huì)改變模板方法中的頂級(jí)邏輯。而鉤子方法的使用只是對(duì)模板方法中邏輯的控制,影響的是模板方法的結(jié)果,并不會(huì)改變?cè)羞壿嫛?/p>
模板方法模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
1)良好的封裝性。把公有的不變的方法封裝在父類,而子類負(fù)責(zé)實(shí)現(xiàn)具體邏輯。
2)良好的擴(kuò)展性:增加功能由子類實(shí)現(xiàn)基本方法擴(kuò)展,符合單一職責(zé)原則和開(kāi)閉原則。
3)復(fù)用代碼。
缺點(diǎn)
1)由于是通過(guò)繼承實(shí)現(xiàn)代碼復(fù)用來(lái)改變算法,靈活度會(huì)降低。
2)子類的執(zhí)行影響父類的結(jié)果,增加代碼閱讀難度。
總結(jié)
模板方法模式看上去簡(jiǎn)單,但是整個(gè)模式涉及到的都是面向?qū)ο笤O(shè)計(jì)的核心,比如繼承封裝,基于繼承的代碼復(fù)用,方法的實(shí)現(xiàn)等等。當(dāng)中還有涉及到一些關(guān)鍵詞的使用,也是我們Java編程中需要掌握的基礎(chǔ)。總體來(lái)說(shuō),模板方法模式是很好的學(xué)習(xí)對(duì)象。下一篇是中介者模式,您的點(diǎn)贊和關(guān)注是我的動(dòng)力,再會(huì)!
更多精彩干貨關(guān)注“AndroidJet的開(kāi)發(fā)之路”公眾號(hào)
設(shè)計(jì)模式Java源碼GitHub下載:https://github.com/jetLee92/D...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/68265.html
摘要:咦這一層一層上報(bào)就涉及到這次的責(zé)任鏈模式。責(zé)任鏈模式和觀察者模式存在一個(gè)共同點(diǎn),就是傳遞責(zé)任鏈模式是一級(jí)一級(jí)的傳遞,形成一條鏈,鏈節(jié)點(diǎn)處理者之間是存在傳遞關(guān)系的。這是責(zé)任鏈模式和觀察者模式的區(qū)別,也是責(zé)任鏈模式的核心。 今天來(lái)說(shuō)說(shuō)程序員小猿和產(chǎn)品就關(guān)于需求發(fā)生的故事。前不久,小猿收到了產(chǎn)品的需求。 產(chǎn)品經(jīng)理:小猿,為了迎合大眾屌絲用戶的口味,我們要放一張圖,要露點(diǎn)的。 小猿:........
摘要:看起來(lái)沒(méi)有集合框架,線程,等那么耀眼,但它可是很多框架的基礎(chǔ)啊回復(fù)反射查看相關(guān)文章,先把基礎(chǔ)學(xué)會(huì),后面的得用到它。 回頭看看, 我進(jìn)入Java 領(lǐng)域已經(jīng)快15個(gè)年頭了, 雖然學(xué)的也一般, 但是分享下我的心得,估計(jì)也能幫大家少走點(diǎn)彎路。[入門]我在2001年之前是C/C++陣營(yíng), 有C和面向?qū)ο蟮幕A(chǔ), 后來(lái)轉(zhuǎn)到Java ,發(fā)現(xiàn)沒(méi)有指針的Java真是好簡(jiǎn)單, 另外Java 的類庫(kù)好用的讓...
摘要:會(huì)一直完善下去,歡迎建議和指導(dǎo),同時(shí)也歡迎中用到了那些設(shè)計(jì)模式中用到了那些設(shè)計(jì)模式這兩個(gè)問(wèn)題,在面試中比較常見(jiàn)。工廠設(shè)計(jì)模式使用工廠模式可以通過(guò)或創(chuàng)建對(duì)象。 我自己總結(jié)的Java學(xué)習(xí)的系統(tǒng)知識(shí)點(diǎn)以及面試問(wèn)題,已經(jīng)開(kāi)源,目前已經(jīng) 41k+ Star。會(huì)一直完善下去,歡迎建議和指導(dǎo),同時(shí)也歡迎Star: https://github.com/Snailclimb... JDK 中用到了那...
閱讀 1857·2021-11-11 16:55
閱讀 2655·2021-08-27 13:11
閱讀 3695·2019-08-30 15:53
閱讀 2362·2019-08-30 15:44
閱讀 1480·2019-08-30 11:20
閱讀 1101·2019-08-30 10:55
閱讀 992·2019-08-29 18:40
閱讀 3115·2019-08-29 16:13