image
前言
??模板方法可以認為是23種設計模式中最簡單的一種了,并且生活中能找到很多的場景浆熔。模板方法雖然簡單但是有些細節(jié)我們還是不能忽視的。
定義
- 模板方法是一種行為類設計模式。
- 模板方法是一個定義在父類的方法革半,在模板方法中會調用多個定義在父類的其他方法,而這些方法有可能只是抽象方法并沒有實現(xiàn)流码。
- 模板方法僅決定這些抽象方法的執(zhí)行順序又官,這些抽象方法的實現(xiàn)由子類負責,并且子類不允許重寫模板方法漫试。
應用場景
- 多個子類有公共的方法六敬,并且邏輯相同。
- 重要驾荣,復雜的算法外构,可以把核心算法設計為模板方法。
優(yōu)點
- 封裝不變部分秘车,擴展可變部分典勇。
- 提取公共部分代碼,便于維護叮趴。
- 行為由父類控制割笙,子類實現(xiàn)。
??把認為是不變部分的算法封裝到父類的實現(xiàn),而可變部分的則可以通過繼承來繼續(xù)擴展伤溉“懵耄基本方法是由子類實現(xiàn)的。因此子類可以通過擴展的方式增加相應功能乱顾,符合開閉原則板祝。
缺點
- 對每個不同的實現(xiàn)都需要定義一個子類,這會導致類的個數(shù)增加走净,系統(tǒng)更加龐大券时,設計也更加抽象。
- 父類中的抽象方法由子類實現(xiàn)伏伯,子類執(zhí)行的結果會影響父類的結果橘洞,這導致一種反向的控制結構,它提高了代碼閱讀的難度说搅。
UML模型
image
實例代碼
??場景:我相信每個人每天起床都會經歷: 起床 -> 刷牙 -> 吃早餐 -> 上班 這樣幾個過程炸枣,但是每個人的過程又是不一樣的。
基礎的日常類
public abstract class BaseDaily {
/**
* 起床
*/
protected abstract void getUp();
/**
* 刷牙
*/
protected abstract void brushTeeth();
/**
* 吃早餐
*/
protected abstract void eatBreakfast();
/**
* 去上班
*/
protected abstract void goForWork();
/**
* 開始美好的一天
*/
final void start(){
getUp();
brushTeeth();
eatBreakfast();
goForWork();
}
}
Andy的日常
public class AndyDaily extends BaseDaily {
@Override
protected void getUp() {
System.out.println("andy起床了");
}
@Override
protected void brushTeeth() {
System.out.println("andy用米家牙刷刷牙");
}
@Override
protected void eatBreakfast() {
System.out.println("andy的早餐是油條加豆?jié){");
}
@Override
protected void goForWork() {
System.out.println("andy走路去上班");
}
}
Bob的日常
public class BobDaily extends BaseDaily {
@Override
protected void getUp() {
System.out.println("bob起床了");
}
@Override
protected void brushTeeth() {
System.out.println("bob用飛利浦牙刷刷牙");
}
@Override
protected void eatBreakfast() {
System.out.println("bob的早餐是腸粉");
}
@Override
protected void goForWork() {
System.out.println("bob坐地鐵去上班");
}
}
Jack的日常
public class JackDaily extends BaseDaily {
@Override
protected void getUp() {
System.out.println("jack起床了");
}
@Override
protected void brushTeeth() {
System.out.println("jack用網易牙刷刷牙");
}
@Override
protected void eatBreakfast() {
System.out.println("jack的早餐是拌粉");
}
@Override
protected void goForWork() {
System.out.println("jack開車去上班");
}
}
測試
public class Test {
public static void main(String[] args) {
BaseDaily andyDaily = new AndyDaily();
andyDaily.start();
System.out.println("====================");
BaseDaily jackDaily = new JackDaily();
jackDaily.start();
System.out.println("====================");
BaseDaily bobDaily = new BobDaily();
bobDaily.start();
}
}
運行結果
andy起床了
andy用米家牙刷刷牙
andy的早餐是油條加豆?jié){
andy走路去上班
====================
jack起床了
jack用網易牙刷刷牙
jack的早餐是拌粉
jack開車去上班
====================
bob起床了
bob用飛利浦牙刷刷牙
bob的早餐是腸粉
bob坐地鐵去上班
模板方法擴展
??場景:我相信每個人每天起床都會經歷: 起床 -> 刷牙 -> 吃早餐 -> 上班 這樣幾個步驟弄唧,但是每個人又是不一樣的适肠。但是可能有人,起床晚了候引,就沒時間吃早餐了侯养。那這個時候我們該咋辦呢?
解決方案如下
??修改 BaseDaily 添加一個是否有時間吃早餐的方法背伴,讓自身判斷有沒有時間吃早餐沸毁。同時子類需要增加相應的實現(xiàn)。
BaseDaily
public abstract class BaseDaily {
/**
* 起床
*/
protected abstract void getUp();
/**
* 刷牙
*/
protected abstract void brushTeeth();
/**
* 吃早餐
*/
protected abstract void eatBreakfast();
/**
* 去上班
*/
protected abstract void goForWork();
/**
* 是否有時間吃早餐
* @return 返回 true 或者 false
*/
protected abstract boolean isHaveTimeEatBreakfast();
/**
* 開始美好的一天
*/
final void start(){
getUp();
brushTeeth();
if(isHaveTimeEatBreakfast()){
eatBreakfast();
}
goForWork();
}
}
Andy日常
public class AndyDaily extends BaseDaily {
@Override
protected void getUp() {
System.out.println("andy起床了");
}
@Override
protected void brushTeeth() {
System.out.println("andy用米家牙刷刷牙");
}
@Override
protected void eatBreakfast() {
System.out.println("andy的早餐是油條加豆?jié){");
}
@Override
protected void goForWork() {
System.out.println("andy走路去上班");
}
@Override
protected boolean isHaveTimeEatBreakfast() {
return false;
}
}
Bob日常
public class BobDaily extends BaseDaily {
@Override
protected void getUp() {
System.out.println("bob起床了");
}
@Override
protected void brushTeeth() {
System.out.println("bob用飛利浦牙刷刷牙");
}
@Override
protected void eatBreakfast() {
System.out.println("bob的早餐是腸粉");
}
@Override
protected void goForWork() {
System.out.println("bob坐地鐵去上班");
}
@Override
protected boolean isHaveTimeEatBreakfast() {
return true;
}
}
Jack日常
public class JackDaily extends BaseDaily {
@Override
protected void getUp() {
System.out.println("jack起床了");
}
@Override
protected void brushTeeth() {
System.out.println("jack用網易牙刷刷牙");
}
@Override
protected void eatBreakfast() {
System.out.println("jack的早餐是拌粉");
}
@Override
protected void goForWork() {
System.out.println("jack開車去上班");
}
@Override
protected boolean isHaveTimeEatBreakfast() {
return true;
}
}
測試
public class Test {
public static void main(String[] args) {
BaseDaily andyDaily = new AndyDaily();
andyDaily.start();
System.out.println("====================");
BaseDaily jackDaily = new JackDaily();
jackDaily.start();
System.out.println("====================");
BaseDaily bobDaily = new BobDaily();
bobDaily.start();
}
}
??運行結果如下: 由于andy起床太晚就沒有時間吃早餐了傻寂。
andy起床了
andy用米家牙刷刷牙
andy走路去上班
====================
jack起床了
jack用網易牙刷刷牙
jack的早餐是拌粉
jack開車去上班
====================
bob起床了
bob用飛利浦牙刷刷牙
bob的早餐是腸粉
bob坐地鐵去上班
鉤子方法
??在我們的抽象類中isHaveTimeEatBreakfast()的返回值就是影響了模板方法的執(zhí)行結果,該方法就叫做鉤子方法(HookMethod)携兵。
需要注意的點
- 為了子類防止惡意的操作疾掰,一般模板方法都加上final關鍵字,不允許被重寫徐紧。
- 抽象模板中的基本方法盡量設計為protected類型静檬,符合迪米特法則,不需要暴露的屬性或方法盡量不要設置為protected類型并级。實現(xiàn)類若非必要拂檩,盡量不要擴大父類中的訪問權限。
參考書籍
- 設計模式之禪道第二版
結尾
??如果覺得對你有幫助嘲碧,可以多多評論稻励,多多點贊哦,也可以到我的主頁看看,說不定有你喜歡的文章望抽,可以隨手點個關注哦加矛,謝謝。
??我是不一樣的科技宅煤篙,每天進步一點點斟览,體驗不一樣的生活。我們下期見辑奈!