設計模式之模板方法模式實戰解析

来源:https://www.cnblogs.com/nesger/archive/2019/09/02/11444583.html
-Advertisement-
Play Games

本文微信公眾號「AndroidTraveler」首發。 背景 最近在看《設計模式之禪》,為了能夠更加深入的理解設計模式,達到學以致用。 這邊記錄一下自己的一些感受和看法,並結合具體代碼實戰來進行說明。 模板方法模式 但凡和設計模式掛上鉤,我們總是會覺得「高不可攀」。 然而實際上,設計模式是基於大量實 ...


本文微信公眾號「AndroidTraveler」首發。

背景

最近在看《設計模式之禪》,為了能夠更加深入的理解設計模式,達到學以致用。
這邊記錄一下自己的一些感受和看法,並結合具體代碼實戰來進行說明。

模板方法模式

但凡和設計模式掛上鉤,我們總是會覺得「高不可攀」。
然而實際上,設計模式是基於大量實際代碼的經驗總結,它來自於實際的代碼。
與其說「高不可攀」,其實它反而是比較「接地氣」。
而模板方法模式相信你看完本篇文章之後,會發現,原來這就是模板方法模式,然後就去看你之前的代碼了。

小例子初識模板方法模式

理解設計模式最好的方法就是通過項目開發中的實際場景來說明。

大家做 Android 開發的時候寫 Activity 應該都會看到下麵類似代碼吧?

private void getIntents() {
    // 從 Intent 獲取傳遞過來的一些參數,設置到屬性中
}

private void findViewById() {
    // 通過 findViewById 來初始化各個組件
}

private void setViews() {
    // 給組件設置監聽或者初始狀態
}

假設我每個界面都這樣寫,那麼重覆代碼太多了,很沒必要。
雖然每個方法具體的邏輯不一樣,但是都有這些操作。

這個時候我們第一個想法就是繼承,抽取出一個 BaseActivity。
然後將這些通用代碼都放到了 BaseActivity 裡面,子類再來覆寫就可以了。

但是還有一個問題,那就是,我每次都需要寫下麵代碼:

getIntents();
findViewById();
setViews();

尤其是通用代碼多的時候,有時候手誤可能導致某些界面這三個方法調用順序還不一樣。
那怎麼辦呢?我們可以抽取出一個方法,這個方法代表了這三個方法統一的調用順序,這樣就不怕手誤寫錯了。
而這個方法就是我們的模板方法

public abstract class BaseActivity extends Activity {
    /**
     * 從 Intent 獲取傳遞過來的一些參數,設置到屬性中
     */
    protected abstract void getIntents();

    /**
     * 通過 findViewById 來初始化各個組件
     */
    protected abstract void findViewById();

    /**
     * 給組件設置監聽或者初始狀態
     */
    protected abstract void setViews();

    /**
     * 模板方法
     */
    final public void init() {
        getIntents();
        findViewById();
        setViews();
    }
}

這樣我後面的 Activity 都可以繼承這個 BaseActivity,然後只需要調用 init 方法即可。
至於不同的 Activity 的邏輯我再在三個方法裡面各自實現即可。

鉤子方法

一聽到這個詞,是不是覺得有點「高大上」,似乎很 NB?
然而,聽完我後面的講述,你內心估計

我們上面的方法裡面,並不是所有的 Activity 都有其他 Activity 傳遞數據過來的,因此 getIntents 這個方法不一定所有子類都要調用。
這個時候我們可以提供一個鉤子方法,改動部分代碼如下:

/**
 * 模板方法
 */
final public void init() {
    if (isGetIntents()) {
        getIntents();
    }
    findViewById();
    setViews();
}

/**
 * 鉤子方法,是否需要設置數據,預設為 true
 * @return
 */
protected boolean isGetIntents() {
    return true;
}

可以看到,通過鉤子方法,當我們預設需要獲取數據時,什麼都不用改動,如果我們不需要獲取數據,只需要覆寫我們的鉤子方法 isGetIntents 並返回 false 即可。

好了,有了初步的印象之後,接下來就正式的加深瞭解吧。

定義

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.
定義一個操作中的演算法的框架,而將一些步驟延遲到子類中。使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。

簡單的說就是父類定義了一個模板方法,在這個模板方法裡面有一些特定的步驟。具體的步驟實現留給子類去處理。

父類的模板方法保持了各個子類的共性,模板方法裡面的步驟使得每個子類都有自己的個性。

通用代碼實現

父類:

public abstract class AbstractPatternClass {
    /**
     * 基本方法,模板方法裡面調用
     */
    protected abstract void firstModule();
    /**
     * 基本方法,模板方法裡面調用
     */
    protected abstract void secondModule();

    /**
     * 模板方法,多個基本方法組合
     */
    final public void templateMethod() {
        firstModule();
        secondModule();
    }
}

具體子類:

public class ConcreteClass extends AbstractPatternClass {
    @Override
    protected void firstModule() {
        // TODO 子類實現自己的邏輯
    }

    @Override
    protected void secondModule() {
        // TODO 子類實現自己的邏輯
    }
}

場景使用類:

public class PatternTest {
    public static void main(String[] args) {
        AbstractPatternClass abstractPatternClass = new ConcreteClass();
        // 調用模板方法
        abstractPatternClass.templateMethod();
    }
}

鉤子方法我們上面已經說過了,相信聰明的你知道如何使用,這裡就不再贅述了。

註意點

父類中的基本方法儘量設計為 protected 類型,符合迪米特法則。
父類中的模板方法一般設置為 final,不允許子類覆寫。這樣的目的一個是為了避免子類惡意操作,一個是為了模板的共性。

應用

當你在寫代碼經常用到複製和粘貼快捷鍵時,你就要考慮是不是可以進行抽取。
當你修改一個地方的時候,發現其他地方也要連帶修改,也需要考慮一下。
多個子類有公共方法,並且邏輯基本相同。
複雜的一些演算法之類的,可以讓子類通過基本方法傳遞一些參數,核心邏輯放在模板方法裡面。
重構項目的時候,也可以考慮一下把相同代碼抽取到父類,通過鉤子方法定製化模板。

結語

最後一點就是註意不要濫用設計模式,不要為了設計而設計

參考資料
設計模式之禪(第2版)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • const portfinder = require('portfinder'); const port = await portfinder.getPortPromise(); 兩行代碼 埠搜索範圍 預設情況下,portfinder將開始搜索8000並掃描,直到達到最大埠號(65535) 源碼 ...
  • JS一個重要功能就是操作DOM, 改變頁面顯示。 目錄: 1、基本概念 2、節點類型 3、節點關係 4、節點操作 基本概念 DOM全稱為Document Object Model ,即文檔對象模型,是針對HTML和XML的一個API, 描繪了一個層次化的節點樹,可以添加、移除和修改頁面的某一部分。 ...
  • 雲計算和移動計算令已經很脆弱的身份及訪問管理(IAM)基礎設施更加搖搖欲墜。問題的日益嚴重推動單點登錄、多因數身份驗證、IAM集中化等領域出現相應變革。 " " 幾年前,CISO們就感受到了雲計算和移動計算時代維持安全控制的艱難。隨著雲計算和移動計算的興起,身份和數據安全已經變成了新的安全邊界,企業 ...
  • 雲已經改變了我們工作的方式,且在不遠的將來,這一動作仍將持續。在雲為員工提供各種便利,為公司企業帶來成本節約、價值提升、工序縮減等收益的同時,新的挑戰也隨之而來。Gartner預測,到2020年, 90% 的企業都將管理 由雲和內部解決方案組成的混合IT基礎設施 ,這無疑會使得安全挑戰和困難變得更加 ...
  • JS數組的方法眾多,平時在使用的時候,容易忘記某些不常用的數組方法,而且時長把兩個差不多的方法搞混。而且ES6在ES5的基礎上又新增了一些方法,為了方便記憶,就寫篇博客方便記憶,沒事的時候拿出來看看。 數組方法: 1.push() 用法:在數組的最後一位添加數據,同時返回插入後的數組長度。 var ...
  • RxJS 的操作符(operators)是最有用的,儘管 Observable 是最基本的。操作符最基本的部分(pieces)就是以申明的方式允許複雜的非同步代碼組合簡化。 什麼是操作符? 操作符是函數。這裡有兩種操作符: 管道操作符(Pipeable Operators)是可以通過使用 管道傳輸到 ...
  • jQuery對象是一個類數組對象,它保存的是對應的DOM的引用,我們可以直接用[]獲取某個索引內的DOM節點,也可以用get方法獲取某個索引內的DOM節點,還可以用toArray()方法把jQuery對象一次性轉換成一個數組,例如: 將DOM對象轉換為jQuery對象就更方便了,直接放到jQuery ...
  • 希望它可以像鋼鐵俠中的 Jarvis 一樣幫我們解決資源的管控問題。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...