模板方法模式

解釋

定義一個操作中的算法的框架,而將一些步驟延遲到子類中。使得子類可以不改變一個算法的結(jié)構(gòu)可重定義改算法的某些特定步驟(通俗理解:將方法的實現(xiàn)延遲到子類)

類圖

模板模式類圖

應(yīng)用場景

  1. 多個子類有公有的方法,并且邏輯基本相同
  2. 重要、復(fù)雜的算法,可以把核心算法設(shè)計為模版方法,周邊的相關(guān)細(xì)節(jié)功能則由各個子類實現(xiàn)
  3. 重構(gòu)時,模板方法模式是一個經(jīng)常使用的模式,把相同的代碼抽取到父類中,然后通過鉤子函數(shù)(見下文解釋)約束其行為

寫法

  1. 聲明抽象父類,抽象公有方法
  2. 延遲到子類實現(xiàn)抽象方法
  3. 通過鉤子函數(shù)約束父親行為(可選)

通用代碼

/**
 * Created by zs on 2017/3/17.
 *
 * 抽象模板類
 */
public abstract class AbstractClass {

    //基本方法
    protected abstract void doSomething();

    //基本方法
    protected abstract void doAnything();

    public void templateMethod(){
        //調(diào)用基本方法,完成相關(guān)邏輯
        this.doAnything();
        this.doSomething();
    }
}


/**
 * Created by zs on 2017/3/17.
 *
 * 具體模板類
 */
public class ConcreteClass1 extends AbstractClass {

    @Override
    protected void doSomething() {
        //to do you work ...
    }

    @Override
    protected void doAnything() {
        //to do you work ...
    }
}


/**
 * Created by zs on 2017/3/17.
 *
 * 具體模板類
 */
public class ConcreteClass2 extends AbstractClass {

    @Override
    protected void doSomething() {
        //to do you work ...
    }

    @Override
    protected void doAnything() {
        //to do you work ...
    }
}


/**
 * Created by zs on 2017/3/17.
 *
 * 場景類
 */
public class Client {
    public static void main(String[] args) {
        AbstractClass class1 = new ConcreteClass1();
        AbstractClass class2 = new ConcreteClass2();

        //調(diào)用模板方法
        class1.templateMethod();
        class2.templateMethod();
    }
}

多說一句

抽象模板中的基本方法盡量設(shè)計為protected類型,符合迪米特法則(請看下文),不需要暴露的屬性和方法盡量不要設(shè)置為protected類型,實現(xiàn)類若非必要,盡量不要擴(kuò)大父類中的訪問權(quán)限

那么什么是迪米特法則(LoD)呢:
通俗理解:一個類應(yīng)該對自己需要耦合或調(diào)用的類知道的最少,你(被耦合或調(diào)用的類)的內(nèi)部是如何復(fù)雜都和我沒關(guān)系,那是你的事情,我就知道你提供的這么多的public 方法,我就調(diào)用這么多,其他的我一概不關(guān)系。

解釋分析:

  1. 只和朋友交流 一個類只和朋友交流,不與陌生類交流
  2. 朋友間也是有距離的,迪米特法則要求類 “羞澀” 一點,盡量不要對外公布太多的public方法和非靜態(tài)的public變量,盡量內(nèi)斂
  3. 是自己的就是自己的,如果一個方法放在本類中,既不增加類間關(guān)系,也對本類不產(chǎn)生負(fù)面影響,那就放在本類中

擴(kuò)展

問題:父類的模板方法約定了基本方法(父類抽象方法)的執(zhí)行,但是子類無法私人訂制是否要執(zhí)行某一個基本方法?

解決方案:鉤子方法
鉤子方法:影響模板方法執(zhí)行結(jié)果的方法

一言不合上代碼:

/**
 * Created by zs on 2017/3/17.
 *
 * 抽象模板類
 */
public abstract class AbstractClass {

    //基本方法
    protected abstract void doSomething();

    //基本方法
    protected abstract void doAnything();

    //鉤子方法
    protected boolean isExecuteSomething(){
        return true;
    }

    //模板方法
    public void templateMethod(){
        //調(diào)用基本方法,完成相關(guān)邏輯
        this.doAnything();
        
        //是否執(zhí)行,由子類決定
        if(isExecuteSomething()){
            this.doSomething();
        }
    }
}


/**
 * Created by zs on 2017/3/17.
 *
 * 具體模板類
 */
public class ConcreteClass1 extends AbstractClass {

    @Override
    protected void doSomething() {
        // to do you work...
    }

    @Override
    protected void doAnything() {
        //to do you work ...
    }

    @Override
    protected boolean isExecuteSomething() {
        return false;
    }
}


/**
 * Created by zs on 2017/3/17.
 *  * 具體模板類
 */
public class ConcreteClass2 extends AbstractClass {

    @Override
    protected void doSomething() {
        //to do you work ...
    }

    @Override
    protected void doAnything() {
        //to do you work ...
    }
}

曲線救國

問題:父類怎么調(diào)用子類的方法?能?不能?
回答:能
解決方案:

  1. 把子類傳遞到父類的有參構(gòu)造中,然后調(diào)用
  2. 使用反射的方式調(diào)用(你使用了反射還有誰不能差遣的,還有誰......還有誰......)
  3. 父類調(diào)用子類的靜態(tài)方法

自嘲:這三種方法都是直接調(diào)用子類的方法,項目中允許使用嗎?不允許!為什么要用父類調(diào)用子類的方法,如果一定要調(diào)用子類,那為什么要繼承它呢?

換個姿勢:父類建立框架,子類重寫了父類部分的方法后,再調(diào)用父類繼承的方法,產(chǎn)生不同的結(jié)果,這一修改子類,影響父類的行為,曲線救國的方式實現(xiàn)了父親依賴子類的場景。

一言不合再上代碼:

/**
 * Created by zs on 2017/3/17.
 *
 * 抽象模板類
 */
public abstract class AbstractClass {

    //基本方法
    protected abstract void doSomething();

    //基本方法
    protected abstract void doAnything();

    //模板方法
    public void templateMethod(){
        //調(diào)用基本方法,完成相關(guān)邏輯
        this.doAnything();
        this.doSomething();

    }
}



/**
 * Created by zs on 2017/3/17.
 *
 * 具體模板類
 */
public class ConcreteClass1 extends AbstractClass {

    @Override
    protected void doSomething() {
        // to do you work...

        //父類調(diào)用子類
        sonMethod();

        //to do you work...
    }

    @Override
    protected void doAnything() {
        //to do you work ...
    }

    //子類方法
    private void sonMethod(){
        // to do you work
    }
}

優(yōu)缺點

優(yōu)點:

  1. 封裝不變部分,擴(kuò)展可變部分
  2. 提取公共部分代碼,便于維護(hù)
  3. 行為由父類控制,子類實現(xiàn)

缺點:
子類執(zhí)行的結(jié)果影響了父類的結(jié)果,也就是子類產(chǎn)生了影響,這在復(fù)雜的項目中,會帶來代碼閱讀的難度

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容