欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

分析設(shè)計(jì)模式之模板方法Java實(shí)現(xiàn)

 更新時(shí)間:2021年06月23日 11:35:41   作者:盛開(kāi)的太陽(yáng)  
所謂模板方法模式,就是一個(gè)對(duì)模板的應(yīng)用,就好比老師出試卷,每個(gè)人的試卷都是一樣的,這個(gè)原版試卷就是一個(gè)模板,可每個(gè)人寫(xiě)在試卷上的答案都是不一樣的,這就是模板方法模式。它的主要用途在于將不變的行為從子類搬到超類,去除了子類中的重復(fù)代碼

一、什么是模板方法設(shè)計(jì)模式

從字面意義上理解, 模板方法就是定義出來(lái)一套方法, 作為模板, 也就是基礎(chǔ)。 在這個(gè)基礎(chǔ)上, 我們可以進(jìn)行加工,實(shí)現(xiàn)個(gè)性化的實(shí)現(xiàn)。比如:一日餐三. 早餐, 中餐, 晚餐. 每個(gè)人都要吃三餐, 但每個(gè)人的三餐吃的可能都不一樣. 一日三餐定義了模板--早中晚, 每個(gè)人的三餐就是模板的具體實(shí)現(xiàn).

1.1、模板方法的用途

  • 將不變的行為從子類搬到超類,去除了子類中的重復(fù)代碼
  • 規(guī)范子類的結(jié)構(gòu)

1.2、模板方法的定義

定義一個(gè)操作中的算法骨架,而將算法的一些步驟延遲到子類中,使得子類可以不改變?cè)撍惴ńY(jié)構(gòu)的情況下重定義該算法的某些特定步驟。它是一種類行為型模式。

二、定義模板方法的步驟

2.1、定義模板類

通常模板類是抽象類,負(fù)責(zé)給出算法的輪廓或者框架。他是有若干個(gè)模板方法和若干個(gè)基本方法構(gòu)成。

1.模板方法

定義了算法的骨架, 定義了方法調(diào)用的順序, 其中包含一個(gè)或者多個(gè)基本方法

2.基本方法

基本算法有三種類型:

​a) 抽象方法:子類必須重寫(xiě)的方法。沒(méi)有默認(rèn)實(shí)現(xiàn)。

​b)具體方法:父類定義的默認(rèn)實(shí)現(xiàn),有實(shí)現(xiàn)邏輯,可以被具體的子類繼承或重寫(xiě)

​c)鉤子方法:判斷的邏輯方法和需要子類重寫(xiě)的空方法兩種。

2.2、定義具體子類

具體子類,也就是具體的實(shí)現(xiàn)類, 實(shí)現(xiàn)抽象類中的抽象方法。他們是抽象的模板方法中一個(gè)組成部分。

2.3、定義客戶端調(diào)用

客戶端調(diào)用抽象類, 實(shí)例化的時(shí)候?qū)嵗唧w類, 只需要調(diào)用抽象類的模板方法就可以了。

2.4 下抽象類和子類之間的UML圖和源碼實(shí)現(xiàn)

1.UML圖

從圖中可以看出抽象類的結(jié)構(gòu)可以定義三類方法。 可以有一個(gè)也可以有多個(gè)。子類必須需要實(shí)現(xiàn)抽象類中的抽象方法,可以選擇性重寫(xiě)父類的具體方法。子類實(shí)現(xiàn)接口的時(shí)候,要多思考設(shè)計(jì)模式的六大原則。

2.源碼

先定義抽象類, 也就是框架。

package com.lxl.www.designPatterns.templatePattern.template;

/**
 * 抽象類, 定義模板
 */
public abstract class AbstractClass {

    /**
     * 定義模板方法
     * 規(guī)范了流程的框架
     */
    public void templateMethod() {
        // 先調(diào)用具體方法
        specificMethod();
        // 在調(diào)用抽象方法
        abstractMethod();
    }

    /**
     * 具體方法
     */
    public void specificMethod() {
        // 具體的公共邏輯, 父子類通用
        System.out.println("具體方法---父子類通用邏輯");
    }

    /**
     * 抽象方法
     *
     * 抽象方法, 子類必須重寫(xiě)
     */
    public abstract void abstractMethod();

}

在定義具體的實(shí)現(xiàn)類, 實(shí)現(xiàn)父類的抽象方法

package com.lxl.www.designPatterns.templatePattern.template;

/**
 * 具體實(shí)現(xiàn)類
 */
public class ConcreteClass extends AbstractClass{

    /**
     * 重寫(xiě)父類的抽象方法
     */
    @Override
    public void abstractMethod() {
        System.out.println("具體實(shí)現(xiàn)類--重寫(xiě)父類的抽象方法");
    }
}

最后定義客戶端調(diào)用

package com.lxl.www.designPatterns.templatePattern.template;

/**
 * 模板方法客戶端
 */
public class TemplateClient {
    public static void main(String[] args) {
        AbstractClass abstractClass = new ConcreteClass();
        abstractClass.templateMethod();
    }
}

運(yùn)行結(jié)果:

具體方法---父子類通用邏輯

具體實(shí)現(xiàn)類--重寫(xiě)父類的抽象方法

對(duì)照模板方法設(shè)計(jì)模式,我們來(lái)看一個(gè)具體的案例。

三、案例

3.1、案例1: 一日規(guī)劃

每個(gè)人的一日安排都有三餐, 早餐, 中餐,晚參。 但每個(gè)人的三餐食物不盡相同,我們來(lái)看看每個(gè)人的三餐變化, 以及三餐前后要做的事情。

package com.lxl.www.designPatterns.templatePattern.oneDayArrangement;

/**
 * 一日三餐抽象類
 */
public abstract class ArrangementAbstract {

    /**
     * 模板方法
     * 規(guī)定了一天的框架
     */
    public void templateMethod() {
        System.out.println("一日安排如下: ");
        getUp();
        breakfast();
        lunch();
        dinner();
        getDown();
    }

    public void getUp() {
        System.out.println("起床");
    }

    public void getDown() {
        System.out.println("睡覺(jué)");
    }

    /**
     * 早餐抽象類
     */
    public abstract void breakfast() ;

    /**
     * 午餐抽象類
     */
    public abstract void lunch();

    /**
     * 晚餐抽象類
     */
    public abstract void dinner();

}

定義一日三餐抽象類。每個(gè)人的日程安排都是,起床,早餐,中餐,晚餐,睡覺(jué)。 其中起床和睡覺(jué)是每個(gè)人都要做的事情,三餐也是,但三餐的食物不同,于是我們將三餐定義為抽象

一日安排實(shí)現(xiàn)類

package com.lxl.www.designPatterns.templatePattern.oneDayArrangement;

/**
 * 張三的一日三餐安排
 */
public class PersonArrangement extends ArrangementAbstract{
    private String name;
    public PersonArrangement(String name) {
        this.name = name;
    }

    /**
     * 早餐抽象類
     */
    public void breakfast(){
        System.out.println(name + "--早餐吃牛奶面包");
    }

    /**
     * 午餐抽象類
     */
    public void lunch() {
        System.out.println(name + "--中餐吃食堂");
    }

    /**
     * 晚餐抽象類
     */
    public void dinner() {
        System.out.println(name + "--晚餐吃水果");
    }

}

客戶端調(diào)用

public class Client {
    public static void main(String[] args) {
        ArrangementAbstract zhangsan = new PersonArrangement("張三");
        zhangsan.templateMethod();
    }
}

運(yùn)行結(jié)果:

一日安排如下:
起床
張三--早餐吃牛奶面包
張三--中餐吃食堂
張三--晚餐吃水果
睡覺(jué)

可以看出, 完全按照模板方法的步驟實(shí)現(xiàn)。

3.2、案例2: 鉤子方法

我們上面說(shuō)了, 模板方法設(shè)計(jì)模式中, 基本方法包括抽象方法,具體方法和鉤子方法.
如果能夠使用好鉤子方法, 可以在程序中完美實(shí)現(xiàn)子類控制父類的行為. 我們來(lái)看下面的案例:

我們?cè)诔橄蠓椒ㄖ卸x一個(gè)鉤子方法hookMethod(), 在模板方法templateMethod()中,鉤子方法控制了代碼的流程.

UML圖:

源代碼:

package com.lxl.www.designPatterns.templatePattern.hookMethod;

/**
 * 抽象類, 定義模板
 */
public abstract class AbstractClass {

    /**
     * 定義模板方法
     * 規(guī)范了流程的框架
     */
    public void templateMethod() {
        // 調(diào)用具體方法
        specificMethod();
        // 鉤子方法控制下一步驟
        if (hookMethod()) {
            // 調(diào)用抽象方法
            abstractMethod();
        }
    }

    /**
     * 具體方法
     */
    public void specificMethod() {
        // 具體的公共邏輯, 父子類通用
        System.out.println("具體方法---父子類通用邏輯");
    }

    /**
     * 鉤子方法
     * 鉤子方法是有具體實(shí)現(xiàn)的,
     */
    public boolean hookMethod() {
        return true;
    }

    /**
     * 抽象方法
     *
     * 抽象方法, 子類必須重寫(xiě)
     */
    public abstract void abstractMethod();

}

定義具體實(shí)現(xiàn)

/**
 * 具體實(shí)現(xiàn)類
 */
public class ConcreteClass extends AbstractClass {

    /**
     * 重寫(xiě)父類的抽象方法
     */
    @Override
    public void abstractMethod() {
        System.out.println("具體實(shí)現(xiàn)類--重寫(xiě)父類的抽象方法");
    }

    /**
     * 鉤子方法
     * @return
     */
    @Override
    public boolean hookMethod() {
        System.out.println("重寫(xiě)了父類的鉤子方法, 反向控制父類的行為");
        return false;
    }
}

重寫(xiě)了鉤子方法, 反向控制父類的行為

public class TemplateClient {
    public static void main(String[] args) {
        AbstractClass abstractClass = new ConcreteClass();
        abstractClass.templateMethod();
    }
}

運(yùn)行結(jié)果

具體方法---父子類通用邏輯
重寫(xiě)了父類的鉤子方法, 反向控制父類的行為

如果子類鉤子方法 HookMethod() 的代碼改變,則程序的運(yùn)行結(jié)果也會(huì)發(fā)生改變。

四、模板方法的優(yōu)缺點(diǎn)

4.1、優(yōu)點(diǎn)

1.規(guī)范了框架, 封裝了不變的部分, 擴(kuò)展了可變的部分. 父類定義框架, 并抽象了公共不變的部分, 子類通過(guò)重寫(xiě)擴(kuò)展完善了框架的實(shí)現(xiàn)。

2.使用了"開(kāi)閉原則", 對(duì)擴(kuò)展開(kāi)放, 對(duì)修改關(guān)閉. 子類可以通過(guò)重寫(xiě)父類的抽象方法來(lái)擴(kuò)展父類的實(shí)現(xiàn)。

3.行為集中有父類控制, 規(guī)范流程。

4.2、缺點(diǎn)

1.每一種實(shí)現(xiàn)都需要定義一個(gè)具體實(shí)現(xiàn)類, 增加類的數(shù)量, 系統(tǒng)更加復(fù)雜。

2.繼承的缺點(diǎn), 一旦父類增加一個(gè)抽象方法, 所有子類都需要增加. 這一點(diǎn)違背"開(kāi)閉原則"。

3.父類中的抽象方法由子類實(shí)現(xiàn), 子類的執(zhí)行結(jié)果影響父類, 這種"反向控制"結(jié)構(gòu), 會(huì)增加代碼的復(fù)雜性。

五、使用場(chǎng)景

1.算法的整體步驟是固定的,但個(gè)別部分容易發(fā)生變化時(shí),可以考慮使用模板方法設(shè)計(jì)模式,將容易發(fā)生變化的部分抽象出來(lái),提供給子類去實(shí)現(xiàn)。

2.當(dāng)多個(gè)子類存在公共的行為時(shí),可以將其提取出來(lái)并集中到一個(gè)公共父類中以避免代碼重復(fù)。首先,要識(shí)別現(xiàn)有代碼中的不同之處,并且將不同之處分離為新的操作。最后,用一個(gè)調(diào)用這些新的操作的模板方法來(lái)替換這些不同的代碼。

3.當(dāng)需要控制子類的擴(kuò)展時(shí),模板方法只在特定點(diǎn)調(diào)用鉤子操作,這樣就只允許在這些點(diǎn)進(jìn)行擴(kuò)展。

4.重構(gòu)時(shí),模板方法模式是一個(gè)經(jīng)常使用到的模式,把相同的代碼抽取到父類中,通過(guò)鉤子函數(shù)約束其行為

六、對(duì)設(shè)計(jì)模式六大原則的應(yīng)用思考

1.單一職責(zé)原則: 一個(gè)方法只有一個(gè)引起變化的原因, 這個(gè)不太好看出, 要開(kāi)子類代碼的具體實(shí)現(xiàn)

2.里式替換原則: 父類出現(xiàn)的地方都可以使用子類替換,并且結(jié)果保持一致. 子類重寫(xiě)了父類的方法。 模板方法設(shè)計(jì)模式可能違背里式替換原則, 不過(guò),這正是能夠“反向控制”的原理

3.接口隔離原則: 依賴于最小的單一接口, 而不是胖接口. 符合

4.依賴倒置原則: 依賴于抽象, 而不是依賴于具體. 符合

5.迪米特法則: 最少知識(shí)原則. 之和朋友溝通, 減少和朋友的溝通. 這個(gè)需要看子類具體實(shí)現(xiàn)是否符合

6.開(kāi)閉原則: 違背開(kāi)閉原則, 一旦父類增加一個(gè)抽象方法, 所有子類都需要對(duì)應(yīng)增加

以上就是分析設(shè)計(jì)模式之模板方法的詳細(xì)內(nèi)容,更多關(guān)于設(shè)計(jì)模式 模板方法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論