近日,ofo小黃車宣佈入駐法國巴黎,正式進入全球第20個國家,共享單車已然改變了咱們的出行方式。就拿我本身來講,每當下班出地鐵的第一件事,以光速鎖定一輛共享單車,百米衝刺的速度搶在別人以前佔領它。git
而你們都是重複着一樣的動做,拿出手機開鎖、騎車、上鎖、結算,哇~這是何等壯觀的場景,甚至還有的不用開鎖直接把車騎走的,鎖壞了嘛。github
爲何要用模板方法模式算法
如今共享單車以開鎖的方式來分,通常有掃碼開鎖和密碼開鎖兩種,來看共享單車使用流程的實現。編程
正常的思惟邏輯是,抽象一個父類,子類繼承父類並實現父類方法。OK,看抽象類代碼:設計模式
public abstract class AbstractClass {ide
// 開鎖 public abstract void unlock(); // 騎行 public abstract void ride(); // 上鎖 public abstract void lock(); // 結算 public abstract void pay(); // 用戶使用 public abstract void use();
}
抽象類定義了咱們使用共享單車的幾個基本流程,如今有兩種不一樣開鎖方式單車的使用,都繼承抽象類,代碼以下:學習
//
public class ScanBicycle extends AbstractClass {this
@Override public void unlock() { System.out.println("掃碼開鎖"); } @Override public void ride() { System.out.println("騎起來很拉風"); } @Override public void lock() { System.out.println("上鎖"); } @Override public void pay() { System.out.println("結算"); } @Override public void use() { unlock(); ride(); lock(); pay(); }
}
以上是經過掃碼方式開鎖騎行,再來看密碼開鎖騎行,代碼以下:設計
public class CodeBicycle extends AbstractClass {code
@Override public void unlock() { System.out.println("密碼開鎖"); } @Override public void ride() { System.out.println("騎起來很拉風"); } @Override public void lock() { System.out.println("上鎖"); } @Override public void pay() { System.out.println("結算"); } @Override public void use() { unlock(); ride(); lock(); pay(); }
}
好了,兩種方式都定義好了,看客戶端的調用:
public class Client {
public static void main(String[] args) { ScanBicycle scanBicycle = new ScanBicycle(); scanBicycle.use(); System.out.println("========================"); CodeBicycle codeBicycle = new CodeBicycle(); codeBicycle.use(); }
}
結果以下:
掃碼開鎖
騎起來很拉風
上鎖
掃碼開鎖
騎起來很拉風
上鎖
結算
相信都已經看出代碼的問題,use方法的實現是同樣的,也就是代碼重複了,這是病必須得治,藥方就是模板方式模式。
模板方法模式
定義
定義抽象類而且聲明一些抽象基本方法供子類實現不一樣邏輯,同時在抽象類中定義具體方法把抽象基本方法封裝起來,這就是模板方法模式。
UML
模板方法模式
模板方法模式涉及到的角色有兩個角色:
模板方法模式還涉及到如下方法的概念:
基本方法
抽象方法:由抽象模板角色聲明,abstract修飾,具體模板角色實現。
鉤子方法:由抽象模板角色聲明並實現,具體模板角色可實現加以擴展。
具體方法:由抽象模板角色聲明並實現,而子類並不實現。
模板方法
抽象模板角色聲明並實現,負責對基本方法的調度,通常以final修飾,不容許具體模板角色重寫。模板方法通常也是一個具體方法。
模式實戰
利用模板方式模式對上面的代碼進行重構,來看抽象模板角色,代碼以下:
public abstract class AbstractClass {
protected boolean isNeedUnlock = true; // 默認須要開鎖 /** * 基本方法,子類須要實現 */ protected abstract void unlock(); /** * 基本方法,子類須要實現 */ protected abstract void ride(); /** * 鉤子方法,子類可實現 * * @param isNeedUnlock */ protected void isNeedUnlock(boolean isNeedUnlock) { this.isNeedUnlock = isNeedUnlock; } /** * 模板方法,負責調度基本方法,子類不可實現 */ public final void use() { if (isNeedUnlock) { unlock(); } else { System.out.println("========鎖壞了,不用解鎖========"); } ride(); }
}
抽象模板角色定義了unlock和ride兩個使用單車的基本方法,還有一個鉤子方法,用來控制模板方法邏輯順序,核心是use模板方法,用final修飾,該方法完成對基本方法調度。注意,模板方法中對基本方法的調度是有順序有規則的。還有一點,基本方法都是protected修飾的,由於基本方法都是在以public修飾的模板方法中調用,而且能夠由子類實現,並不須要暴露給其餘類調用。
如今來看兩個具體模板角色的實現:
// 掃碼開鎖的單車
public class ScanBicycle extends AbstractClass {
@Override protected void unlock() { System.out.println("========" + "掃碼開鎖" + "========"); } @Override protected void ride() { System.out.println(getClass().getSimpleName() + "騎起來很拉風"); } protected void isNeedUnlock(boolean isNeedUnlock) { this.isNeedUnlock = isNeedUnlock; }
}
// 密碼開鎖的單車
public class CodeBicycle extends AbstractClass {
@Override protected void unlock() { System.out.println("========" + "密碼開鎖" + "========"); } @Override protected void ride() { System.out.println(getClass().getSimpleName() + "騎起來很拉風"); } protected void isNeedUnlock(boolean isNeedUnlock) { this.isNeedUnlock = isNeedUnlock; }
}
能夠看到,相比以前的實現,如今兩個具體類都不須要實現use方法,只負責實現基本方法的邏輯,職責上變得更加清晰了。來看用戶如何使用:
public class Client {
public static void main(String[] args) { ScanBicycle scanBicycle = new ScanBicycle(); scanBicycle.use(); CodeBicycle codeBicycle = new CodeBicycle(); codeBicycle.use(); }
}
運行結果以下:
========掃碼開鎖========
ScanBicycle騎起來很拉風
========密碼開鎖========
CodeBicycle騎起來很拉風
當我以百米衝刺的速度跑到共享單車面前時,發現這輛車的鎖是壞掉的,也就是不用開鎖,免費的,騎回家收藏也沒問題。在代碼中只要調用鉤子方法isNeedUnlock就好,實現以下:
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(); }
}
運行結果以下:
========鎖壞了,不用解鎖========
ScanBicycle騎起來很拉風
========密碼開鎖========
CodeBicycle騎起來很拉風
上面提到模板方法對基本方法的調度是有順序的,也就是說模板方法中的邏輯是不可變的,子類只實現能夠被實現的基本方法,但不會改變模板方法中的頂級邏輯。而鉤子方法的使用只是對模板方法中邏輯的控制,影響的是模板方法的結果,並不會改變原有邏輯。
模板方法模式的優缺點
優勢
1)良好的封裝性。把公有的不變的方法封裝在父類,而子類負責實現具體邏輯。
2)良好的擴展性:增長功能由子類實現基本方法擴展,符合單一職責原則和開閉原則。
3)複用代碼。
缺點
1)因爲是經過繼承實現代碼複用來改變算法,靈活度會下降。
2)子類的執行影響父類的結果,增長代碼閱讀難度。
總結
模板方法模式看上去簡單,可是整個模式涉及到的都是面向對象設計的核心,好比繼承封裝,基於繼承的代碼複用,方法的實現等等。當中還有涉及到一些關鍵詞的使用,也是咱們Java編程中須要掌握的基礎。整體來講,模板方法模式是很好的學習對象。下一篇是中介者模式,您的點贊和關注是個人動力,再會!
更多精彩乾貨關注「AndroidJet的開發之路」公衆號
設計模式Java源碼GitHub下載:https://github.com/jetLee92/D...