一分鐘學會《模板方法模式》

前言

只有光頭才能變強。java

文本已收錄至個人GitHub倉庫,歡迎Star:https://github.com/ZhongFuCheng3y/3ygit

在上一篇有讀者說,一分鐘就看完門面模式了,因此今天的標題就取《一分鐘學會模板方法模式》github

回顧前面所寫過的設計模式:面試

不管是面試仍是我的的提高,設計模式是必學的。今天來說解模板方法模式~算法

1、模板方法模式

1.1模板方法模式現實例子

你們都知道,我每次寫原創技術文章,開頭總會有「只有光頭才能變強」。我固然不可能每次寫文章的時候都去複製這句話(由於這樣太麻煩了)。設計模式

我有本身的寫做模板,給你們看一下:框架

個人寫做模板

前言和最後都是固定下來的,至於第一點和第二點就得看是寫什麼文章,寫不一樣的文章對應的內容也是不同的。ide

每次我寫文章的時候,只要在這個模板上添加我本身想寫的東西就行了,就不用每次都複製一遍相同的內容,這樣就大大減小個人工做量啦。ui

1.2回到代碼世界

代碼來源於生活,一樣地我能夠將我寫文章的過程用代碼來描述,你們來看一下。.net

3y每篇文章都會有「前言」和「最後」的內容,3y把這兩個模塊寫出來了。

// 3y的文章模板
public class Java3yWriteArticle {
    
    // 前言
    public void introduction() {
        System.out.println("只有光頭才能變強");
    }

    // 最後
    public void theLast() {
        System.out.println("關注個人公衆號:Java3y");

    }
}

3y寫文章的時候,3y可能就會這樣使用:

// 3y寫文章
    public static void main(String[] args) {

        Java3yWriteArticle writeArticle = new Java3yWriteArticle();

        // 前言
        writeArticle.introduction();

        // 實際內容
        System.out.println("你們好,我是3y,今天來給你們分享我寫的模板方法模式");

        // 最後
        writeArticle.theLast();
    }

這樣是能夠完成3y寫文章的功能,可是這樣作好嗎?這時候3y女友也想寫文章,她的文章一樣也想有「前言」和「最後」兩個模塊,因此3y女友的文章模板是這樣的:

// 3y女友的文章模板
public  class Java3yGFWriteArticle {

    // 前言
    public void introduction() {
        System.out.println("balabalabalalabalablablalab");
    }

    // 最後
    public void theLast() {
        System.out.println("balabalabalalabalablablalab");

    }
}

那3y女友寫文章的時候,可能也會這樣使用:

// 3y女友寫文章
    public static void main(String[] args) {
        Java3yGFWriteArticle java3yGFWriteArticle = new Java3yGFWriteArticle();

        // 前言
        java3yGFWriteArticle.introduction();

        // 實際內容
        System.out.println("3y是傻子,不用管他");

        // 最後
        java3yGFWriteArticle.theLast();

    }

能夠發現3y和3y女友要寫文章的時是要重複調用introduction();theLast();。而且,3y的文章模板和3y女友的文章模板中的「前言」和「最後」只是實現內容的不一樣,卻定義了兩次,明顯就是重複的代碼。面對重複的代碼咱們會作什麼?很簡單,抽取出來!

因而咱們就能夠抽取出一個通用的WriteArticle(爲了方便調用,咱們還將寫文章的步驟封裝成一個方法):

// 通用模板
public abstract class WriteArticle {

    // 每一個人的「前言」都不同,因此抽象(abstract)
    protected abstract void introduction();

    // 每一個人的「最後」都不同,因此抽象(abstract)
    protected abstract void theLast();


    // 實際要寫的內容,每一個人的「實際內容」都不同,因此抽象(abstract)
    protected abstract void actualContent();
    
    // 寫一篇完整的文章(爲了方便調用,咱們將這幾個步驟分裝成一個方法)
    public final void writeAnCompleteArticle() {

        // 前言
        introduction();

        // 實際內容
        actualContent();

        // 最後
        theLast();
    }
}

因此,3y的模板就能夠繼承通用模板,在通用模板上實現本身想要的就行了:

// 3y的文章模板
public  class Java3yWriteArticle extends WriteArticle {

    // 前言
    @Override
    public void introduction() {
        System.out.println("只有光頭才能變強");
    }

    // 最後
    @Override
    public void theLast() {
        System.out.println("關注個人公衆號:Java3y");

    }
    @Override
    protected void actualContent() {
        System.out.println("你們好,我是3y,今天來給你們分享我寫的模板方法模式");
    }
}

一樣地,3y女友的文章模板也是相似的:

// 3y女友的文章模板
public  class Java3yGFWriteArticle extends WriteArticle {

    // 前言
    @Override
    public void introduction() {
        System.out.println("balabalabalalabalablablalab");
    }

    // 最後
    @Override
    public void theLast() {
        System.out.println("balabalabalalabalablablalab");

    }

    @Override
    protected void actualContent() {
        System.out.println("3y是傻子,不用管他");
    }
}

想要真正寫文章的時候就十分方便了:

// 3y寫文章
    public static void main(String[] args) {

        WriteArticle java3ywriteArticle = new Java3yWriteArticle();
        java3ywriteArticle.writeAnCompleteArticle();
    }

	// 3y女友寫文章
    public static void main(String[] args) {
        WriteArticle java3yGFWriteArticle = new Java3yGFWriteArticle();
        java3yGFWriteArticle.writeAnCompleteArticle();
    }

要點:

  • 把公共的代碼抽取出來,若是該功能是不肯定的,那咱們將其修飾成抽象方法。
  • 將幾個固定步驟的功能封裝到一個方法中,對外暴露這個方法,就能夠很是方便調用了。

嗯,上面的就是模板方法模式,就這麼簡單!

1.3模板方法模式介紹

《設計模式之禪》:

定義一個操做中的算法框架,而將一些步驟延遲到子類中。使子類能夠不改變一個算法的結構便可重定義該算法的某些步驟。

根據咱們上面的例子,來說講這段話的含義:

  • 定義一個操做中的算法框架,而將一些步驟延遲到子類中。
    • WriteArticle中有一個writeAnCompleteArticle()方法,該方法定義了發文章的全部步驟,可是這些步驟大可能是抽象的,得由子類來實現。
  • 使子類能夠不改變一個算法的結構便可重定義該算法的某些步驟
    • 外界是經過調用writeAnCompleteArticle()方法來寫文章的,子類若是改變具體的實現就會間接改變了算法的細節。

好比3y在文章模板中的introduction()改了,「只有充錢才能變強」

@Override
    public void introduction() {
        System.out.println("只有充錢才能變強");
    }

咱們沒有碰過writeAnCompleteArticle()的代碼,但再次調用這個方法的時候,具體的實現就會發生改變(由於writeAnCompleteArticle受子類的具體實現影響)

下面咱們看一下模板方法模式的通用類圖:

模板方法模式的通用類圖

在模板方法模式中,也有幾個術語,根據咱們的例子中的註釋,我給你們介紹一下:

// 抽象模板類
public abstract class WriteArticle {


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

    // 基本方法
    protected abstract void theLast();
    
    // 基本方法
    protected abstract void actualContent();

    // 模板方法
    public final void writeAnCompleteArticle() {
        introduction();
        actualContent();
        theLast();
    }
}

// 具體模板類
public class Java3yWriteArticle extends WriteArticle {

    // 實現基本方法
    @Override
    public void introduction() {
        System.out.println("只有充錢才能變強");
    }

    // 實現基本方法
    @Override
    public void theLast() {
        System.out.println("關注個人公衆號:Java3y");
    }

    // 實現基本方法
    @Override
    protected void actualContent() {
        System.out.println("你們好,我是3y,今天來給你們分享我寫的模板方法模式");
    }
}
  • 基本方法:在子類實現,而且在模板方法中被調用
  • 模板方法:定義了一個框架,實現對基本方法的調用,完成固定的邏輯

1.4模板方法的優缺點

優勢:

  • 封裝不變的部分,擴展可變的部分。把認爲是不變的部分的算法封裝到父類,可變部分的交由子類來實現!
  • 提取公共部分的代碼,行爲由父類控制,子類實現!

缺點:

  • 抽象類定義了部分抽象方法,這些抽象的方法由子類來實現,子類執行的結果影響了父類的結果(子類對父類產生了影響),會帶來閱讀代碼的難度!

1.5模板方法模式JDK應用

最經典的就是JUC包下的AQS(AbstractQueuedSynchronizer)了。AQS是什麼?

AQS其實就是一個能夠給咱們實現鎖的框架。內部實現的關鍵是:先進先出的隊列、state狀態

咱們能夠看一下AQS定義的acquire()

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

acquire()至關於模板方法,tryAcquire(arg)至關於基本方法。

tryAcquire方法被多個子類實現

最後

模板方法模式也很簡單呀,一個抽象類有基本方法(等着被子類實現的方法),有模板方法(對外暴露、調用基本方法、定義了算法的框架),那就完事了。

推薦閱讀和參考資料:

樂於分享和輸出乾貨的Java技術公衆號:Java3y。關注便可領取海量的視頻資源!

帥的人都關注了

精彩回顧:

以爲個人文章寫得不錯,不妨點一下

相關文章
相關標籤/搜索