模板方法模式

簡介

Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
定義一個操作中的算法的框架,而將一些步驟延遲到子類中。使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。

模板方法模式(Template Method Pattern) 實際上是封裝了一個固定流程,該流程由幾個步驟組成,具體步驟可以由子類進行不同實現(xiàn),從而讓固定的流程產(chǎn)生不同的結(jié)果。

模板方法模式 非常簡單,其實就是類的繼承機制,但它卻是一個應(yīng)用非常廣泛的模式。

模板方法模式 本質(zhì):抽象封裝流程,具體進行實現(xiàn)

主要解決

當(dāng)完成一個操作具有固定的流程時,由抽象固定流程步驟,具體步驟交給子類進行具體實現(xiàn)(固定的流程,不同的實現(xiàn))。

優(yōu)缺點

優(yōu)點

  • 封裝不變,擴展可變:父類封裝了具體流程以及實現(xiàn)部分不變行為,其它可變行為交由子類進行具體實現(xiàn);
  • 流程由父類控制,子類進行實現(xiàn):框架流程由父類限定,子類無法更改;子類可以針對流程某些步驟進行具體實現(xiàn);

缺點

  • 抽象規(guī)定了行為,具體負責(zé)實現(xiàn),與通常事物的行為相反,會帶來理解上的困難(通俗地說,“父類調(diào)用了子類方法”);

使用場景

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

模式講解

首先來看下 模板方法模式 的通用 UML 類圖:

模板方法模式

從 UML 類圖中,我們可以看到,模板方法模式 主要包含兩種角色:

  • 抽象模板(AbstractClass):抽象模板類,定義了一套算法框架/流程;
  • 具體實現(xiàn)(ConcreteClass):具體實現(xiàn)類,對算法框架/流程的某些步驟進行了實現(xiàn);

以下是 模板方法模式 的通用代碼:

class Client {
    public static void main(String[] args) {
        AbstractClass abc = new ConcreteClassA();
        abc.templateMehthod();
        abc = new ConcreteClassB();
        abc.templateMehthod();
    }

    // 抽象模板類
    static abstract class AbstractClass {
        protected void step1() {
            System.out.println("AbstractClass:step1");
        }

        protected void step2() {
            System.out.println("AbstractClass:step2");
        }

        protected void step3() {
            System.out.println("AbstractClass:step3");
        }

        // 聲明為final方法,避免子類覆寫
        public final void templateMehthod() {
            this.step1();
            this.step2();
            this.step3();
        }
    }

    // 具體實現(xiàn)類A
    static class ConcreteClassA extends AbstractClass {
        @Override
        protected void step1() {
            System.out.println("ConcreateClassA:step1");
        }
    }

    // 具體實現(xiàn)類B
    static class ConcreteClassB extends AbstractClass {
        @Override
        protected void step2() {
            System.out.println("ConcreateClassB:step2");
        }
    }
}

:通常把抽象模板類AbstractClass的模板方法templateMethod定義成final類型,避免子類對其覆寫,并遵命定義算法結(jié)構(gòu)/流程的語義。

舉個例子

例子:小明要炒兩道菜:炒豆芽和炒茄子;
分析:炒菜都有固定步驟:洗菜,熱鍋下油,下菜翻炒,下調(diào)料,起鍋。由于炒菜流程是固定的,而其中有些步驟對不同的菜而言具備不同的操作,因此可以很好地使用 模板方法模式 完成炒菜過程。

具體代碼如下:

class Client {
    public static void main(String[] args) {
        System.out.println("準(zhǔn)備炒豆芽");
        CookVegetable cookVegetable = new CookBeanSprout();
        cookVegetable.cook();

        System.out.println();
        System.out.println("準(zhǔn)備炒茄子");
        cookVegetable = new CookEggplant();
        cookVegetable.cook();
    }

    // 抽象模板類:定義炒菜流程
    static abstract class CookVegetable {
        protected void wash() {
            System.out.println("洗菜");
        }

        protected void pourOil() {
            System.out.println("熱油下鍋");
        }

        protected void fry() {
            System.out.println("下菜翻炒");
        }

        // 具體調(diào)料由菜決定
        protected abstract void pourSauce();

        // 具體炒菜流程
        public final void cook() {
            this.wash();
            this.pourOil();
            this.fry();
            this.pourSauce();
            System.out.println("起鍋吃菜");
        }
    }

    // 豆芽
    static class CookBeanSprout extends CookVegetable {

        @Override
        protected void pourOil() {
            System.out.println("熱鍋少油");
        }

        @Override
        protected void fry() {
            System.out.println("快速翻炒");
        }

        @Override
        protected void pourSauce() {
            System.out.println("加鹽和少量生抽");
        }
    }

    // 茄子
    static class CookEggplant extends CookVegetable {

        @Override
        protected void wash() {
            System.out.println("去除頭尾,然后用水洗下");
        }

        @Override
        protected void pourOil() {
            System.out.println("熱鍋多油");
        }

        @Override
        protected void pourSauce() {
            System.out.println("加鹽和雞精");
        }
    }
}

結(jié)果如下:

準(zhǔn)備炒豆芽
洗菜
熱鍋少油
快速翻炒
加鹽和少量生抽
起鍋吃菜

準(zhǔn)備炒茄子
去除頭尾,然后用水洗下
熱鍋多油
下菜翻炒
加鹽和雞精

我們根據(jù) 模板方法模式,就可以抽象定義炒菜的流程,然后針對不同的菜品,由其子類對某些炒菜步驟進行具體實現(xiàn),這樣就完成了炒菜過程。

最后編輯于
?著作權(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ù)。

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