架構師日記-深入理解軟件設計模式



一、設計模式與編程語言


1.1 什麼是設計模式
設計模式(Design pattern):由軟件開發人員在軟件開發中面臨常見問題的解決方案,是經過長時間的試驗積累總結出來的,它使設計更加靈活和優雅,複用性更好。從實用的角度來看,它代表了某一類問題的最佳實踐。
設計模式到底解決了開發過程中的哪些難題呢,它又是如何來解決的呢?
其核心是 複用和解耦。 使不穩定依賴於穩定、具體依賴於抽象,以此增強軟件設計適應變化的能力。

1.2 什麼是編程範式

要探討設計模式和編程語言的關係,還得從編程範式談起。編程範式一詞最早來自 Robert Floyd 在 1979 年圖靈獎的頒獎演說,是程序員看待程序的觀點,代表了程序設計者認爲程序應該如何被構建和執行的看法,與軟件建模方式和架構風格有緊密關係。
當前主流的編程範式有三種:
  1. 結構化編程(structured programming)
  2. 面向對象編程(object-oriented programming)
  3. 函數式編程(functional programming)
這幾種編程範式之間的關係如下:
  1. 起初是非結構化編程,指令(goto指令)可以隨便跳轉,數據可以隨便引用。後來有了結構化編程,人們把 goto 語句去掉了,約束了指令的方向性,過程之間是單向的,但數據卻是可以全局訪問的;
  2. 後來面向對象編程的時候,人們乾脆將數據與其緊密耦合的方法放在一個邏輯邊界內,約束了數據的作用域,靠關係來查找;
  3. 到函數式編程的時候,人們約束了數據的可變性,通過一系列函數的組合來描述數據,從源到目標映射規則的編排,中間它是無狀態的;
編程範式是抽象的,編程語言是具體的。編程範式是編程語言背後的思想,要通過編程語言來體現。C 語言的主流編程範式是結構化編程,而 Java 語言的主流編程範式是面向對象編程,後來 Java8 開始支持 Lambda 表達式,將函數式編程範式的內容融合進來,同時新誕生的語言一開始就支持多範式,比如 Scala,Go 和 Rust 等。
從結構化編程到面向對象編程,再到函數式編程,抽象程度越來越高(離圖靈機模型越來越遠),與領域問題的距離越來越近。直觀地來講,就是解決現實問題的效率提升了,靈活性和執行效率隨之有所下降。
設計模式無論用什麼語言實現都是可以的,然而由於語言的各自差異化特點,不是每種語言都完美或統一實現各種設計模式。 比如Java裏面有策略模式,那是因爲Java8之前不支持方法傳遞,不能把一個方法當作參數傳給別人,所以有了策略模式。 而JavaScript等語言可以直接傳函數,就根本沒必要造一個策略模式出來。

1.3 什麼是多態特性

面向對象編程語言有三大特性:封裝、繼承和多態。
  1. 封裝即信息隱藏或數據保護,“數據結構"通過暴露有限的訪問接口,授權外部僅能通過"數據結構"提供的方法(函數)來訪問其內部的數據;
  2. 繼承的好處是可以實現代碼複用,但不應過度使用,如果繼承的層次過深就會導致代碼可讀性和可維護性變差。因此建議少用繼承而多用組合模式;
  3. 多態可以分爲變量的多態,方法的多態,類的多態。通常強調的是類的多態,多態的實現是指子類可以替換父類,在實際代碼運行過程中調用子類的方法實現;
多態可以說是面向對象中最重要的一個特性,是解決項目中緊耦合的問題,提高代碼的可擴展性和可複用性的核心,是很多設計模式、設計原則、編程技巧的代碼實現基礎。
多態比較直觀的理解就是去完成某個動作,當不同的對象去完成時會產生出不同的狀態,其作用範圍可以是方法的參數和方法的返回類型。
多態這種特性也需要編程語言提供特殊的語法機制來實現,Java 中多態可以通過"子類繼承父類+子類重寫父類方法+父類引用指向子類對象"的方式實現,還可以通過"接口語法"的方式實現。C++中則使用virtual(虛函數)關鍵字來實現。像一些動態語言如 Python 也可以通過 duck-typing 的語法實現,另外 Go 語言中的"隱藏式接口"也算是 duck-typing。
Python 語言,實現多態示例如下:
class MyFile:    def write(self):        print('I write a message into file.')        class MyDB:    def write(self):        print('I write data into db. ')        def doIt(writer):    writer.write()
def demo(): myFile= MyFile() myDB = MyDB() doIt(myFile) doIt(myDB )


二、設計模式與架構模式

2.1 瞭解架構模式

對給定上下文的軟件架構中常見問題的一種通用的可複用的解決方案,可以爲設計大型軟件系統的各個方面提供相應的指導。它不僅顯示了軟件需求和軟件結構之間的對應關係,而且指定了整個軟件系統的組織和拓撲結構,提供了一些設計決策的基本原理,常見的架構設計模式如下:

2.2 瞭解設計模式

在1995年,有四位編程界的前輩合著了一本書,書名叫做《Design Patterns: Elements of Reusable Object-Oriented Software》,翻譯過來就是《設計模式:可複用面向對象軟件的基礎》,書裏面總共收錄了23種設計模式。這本書是軟件研發領域重要的里程碑,合著此書的四位作者,被業內稱爲GoF(Gang of Four),因此這本書也被人稱爲GoF設計模式。
設計模式按照目的來分類有: 創建、結構、行爲三種,按照作用範圍來分類有: 類模式和對象模式兩種。
  1. 創建型模式:用於創建對象,就是將對象的創建與使用分離。從而降低系統的耦合度,使用者不需要關注對象的創建細節,對象的創建由相關的工廠來完成。
  2. 結構型模式 :描述如何將類,對象,接口之間按某種佈局組成更大的結構。
  3. 行爲型模式 :用於描述程序在運行時複雜的流程控制,即描述多個類或對象之間怎樣相互協作共同完成單個對象都無法單獨完成的任務,它涉及算法與對象間職責的分配。
23種設計模式如下:

2.3 小結
  • 架構模式更像是宏觀戰略層面的設計,設計模式則更像是戰略目標拆解出來的具體任務的實現方案;
  • 軟件架構是軟件的一種搭建形式,往往規定了軟件的模塊組成,通信接口(含通信數據結構),組件模型,集成框架等,往往規定了具體的細節;
  • 設計模式是一種軟件的實現方法,是一種抽象的方法論,是爲了更好地實現軟件而歸納出來的有效方法;
  • 實現一種軟件架構,不同組成部分可能用到不同的設計模式,某個部分也可能可以採用不同的設計模式來實現;


三、應用實踐指南


3.1 適用場景

不使用設計模式也能實現業務訴求,系統也能夠正常運行,爲什麼要使用設計模式呢?
是的,相當一部分場景是不需要進行設計模式的引入的,比如:業務邏輯簡單,業務演進方向不明朗,或者就是一個不需要經常迭代的功能點。但當我們遇到了複雜問題設計的時候,就需要藉助前人的經驗了,而設計模式就是前人爲我們沉澱總結的各種常見問題的解決方案。
那麼多種設計模式,難道我需要全部系統地學習實現一遍,都要閉着眼睛就能寫出來嗎?其實不用,這就跟排序算法一樣,我們只需要記住每種算法的適用範圍和場景就可以了,在有需要的時候,再去深入研究就可以了。以下總結了各種設計模式對應的適用場景:

3.2 場景案例

爲了讓讀者對設計模式有個更加直觀立體的感知,接下來以實際案例爲大家展現一下設計模式在實際場景的應用。案例包含了創建型,結構型,行爲型各種模式類型裏常用的設計模式,比如:
  • 用工廠模式隔離業務實現;
  • 用策略模式消解業務流程分支;
  • 用模板方法模式提取業務分支公共流程;
  • 用建造者模式簡化入參對象的構建難度;
  • 用代理模式橫向擴展通用能力(日誌,異常處理);
  • 用職責鏈模式對請求進行敏感詞,防刷校驗;
  • 用命令模式讓指令擁有了記憶;
中國有個古諺語:“一個和尚挑水喫,兩個和尚擡水喫,三個和尚等水喫。” 我們就通過程序來模擬出家人的寺廟生活。

工廠模式

首先,這三個人是如何成爲和尚的呢?
一號和尚(貧困潦倒型),出生在一個大山裏頭,父母怕他孤單,給他生了5個弟弟,在他9歲那年,恰巧家裏鬧了饑荒,爲了喫上飯,進了寺廟,出了家;
二號和尚(走投無路型),出生在一個湖泊旁邊,因爲生性耿直,18歲那年,走在街頭,路見不平,三拳打死街上惡霸,爲了贖罪,受了戒,墜入空門;
三號和尚(天選之子型),從小敏而好學,性情溫厚,對佛學產生濃厚興趣,13歲那年,爲了繼承和光大佛法,斷了塵緣,皈依佛門。
N號和尚,......
每一個和尚的來歷都不盡相同,但在當下喝不上水,這件事情上,都顯得不重要。重要的是,只要湊足三個和尚,就會沒水喝。那麼寺廟如招收和尚?這裏就可以用到工廠模式的思想。
    // 貧困潦倒產生的和尚過程:1.大山裏;2.鬧饑荒;3.要喫飯;    一號和尚 = HeShangFactoty.getOneHeshang("貧困潦倒型");    // 走投無路產生的和尚過程:1.生性耿直;2.打死惡霸;3.要贖罪;    二號和尚 = HeShangFactoty.getOneHeshang("走投無路型");    // 天選之子產生的和尚過程:1.敏而好學;2.佛學感興趣;3.要廣大佛法;    三號和尚 = HeShangFactoty.getOneHeshang("天選之子型");
以上示例想體現的是工廠模式能將複雜的對象創建和使用進行了分離設計。下面就以和尚喫水這件事情,用程序的方式詳細展現工廠模式的實現思路。按照和尚的人數,分別有挑,擡,等三種實現方式。以下爲基礎代碼實現:
public interface Waterable {    Water getWater();}
public class TiaoShui implements Waterable{ public Water getWater(){ System.out.println("先到山下去!"); return "水是挑上來的!"; }}
public class TaiShui implements Waterable{ public Water getWater(){ System.out.println("先到山下去!"); return "水是擡上來的!"; }}
public class DengShui implements Waterable{ public Water getWater(){ System.out.println("就坐在原地!"); return "水是等不來的!"; }}
具體使用
  
  
  
public class Factory {    /**     * 按照和尚數量生成取水對象     *     * @param heShangNum 和尚數量     * @return     */    public static Waterable getWaterable(Integer heShangNum) {        switch (heShangNum) {            case 1:                return new TiaoShui();            case 2:                return new TaiShui();            case 3:                return new DengShui();            default:                throw new RuntimeException("廟小,裝不下那麼多和尚!");        }    }}

策略模式

按照不同的條件(人數),分別有幾種獲取水的方法:挑,擡,等。可以通過策略模式來實現,前面的實現方式其實就是策略模式和工廠模式的結合。我們再看一下策略模式的具體使用方式如下:
  
  
  
    /**     * 通過入參和尚人數,就可以動態改變Waterable.getWater()的取水模式     * @param heShangNum     * @return     */    public void getWater(Integer heShangNum) {        Waterable waterable = Factory.getWaterable(heShangNum);        Water water = waterable.getWater();// 取水    }
  1. 輸入參數1:挑水模式的實現(對應Tiaoshui實現類);
  2. 輸入參數2:擡水模式的實現(對應Taishui實現類);
  3. 輸入參數3:等不到水模式的實現(對應Dengshui實現類);
通過和尚人數,就可以動態獲得對應的取水實現,即所謂的通過策略實現業務,對於使用方來說(主流程),無需關注取水的具體實現(解耦:業務流程穩定性的設計體現),新增取水方式時,只需要新增一個類實現就可以了,存量的實現和主流程都不會受到影響。

模板方法

我們細化取水過程,取水過程一般需要三步:
  1. 拿起工具(扁擔或者木棍);
  2. 到寺廟南面的小河邊(步行);
  3. 裝滿水帶回寺廟(挑水,擡水,等水)
我們可以將取水流程步驟進行模板化。
  
  
  
public interface Waterable {    Water getWater();}
public abstract class AbstractWaterable implements Waterable { @Override public Water getWater() { takeTool(); toRiver(); return moveWater(); } /** * 拿起工具 */ protected abstract String takeTool();
/** * 到河邊去 */ protected String toRiver() { System.out.println("走過去!"); return "步行"; }
/** * 將水帶回來 * * @return */ protected abstract Water moveWater();}
個性化場景實現
public class TiaoShui extends AbstractWaterable {
@Override protected String takeTool() { return "扁擔"; }
@Override protected Water moveWater() { return "挑水"; }}
public class Taishui extends AbstractWaterable{ @Override protected String takeTool() { return "木棍"; }
@Override protected Water moveWater() { return "擡水"; }}
public class DengShui extends AbstractWaterable{ @Override protected String takeTool() { return "意念"; }
@Override protected String toRiver() { return "一動不動"; }
@Override protected Water moveWater() { return "無水"; }}
具體使用
/**     * 和尚取水:實現一個和尚挑水喝,兩個和尚擡水喝,三個和尚等水喝     */    public void fetchWater(){        //         for (int heShangNum = 1; heShangNum < 4; heShangNum++) {            Waterable waterable = Factory.getWaterable(heShangNum);            Water water = waterable.getWater();        }    }
模板方法講的是流程標準定義和能力複用。示例中,定義了取水的三個階段,選擇工具,出行方式,搬運方式。單看出行方式中,【挑水】和【擡水】複用了模板方法裏的通用實現,【等水】則個性化的重寫了出行方式。

建造者模式

我們取水需要一些工具,按照取水方式(挑,擡,等)可以分爲扁擔+木桶,木棍+木桶,意念(什麼也不需要)等裝備的組合方式。如何定義getWater(ToolBox toolBox)的入參ToolBox,使其能夠按照對應取水方式匹配正確的裝備組合呢?這裏就可以使用建造者模式。
  
  
  
public class ToolBox {    private final String bianDan;    private final String muTong;    private final String muGun;
private ToolBox(TiaoBuilder builder){ this.bianDan=builder.bianDan; this.muTong=builder.muTong; this.muGun = null; } private ToolBox(TaiBuilder builder){ this.bianDan = null; this.muTong = null; this.muGun=builder.muGun; } private ToolBox(DengBuilder builder){ this.bianDan = null; this.muTong = null; this.muGun=null; } public static class TiaoBuilder{ private String bianDan; private String muTong;
public TiaoBuilder setBianDan(String bianDan) { this.bianDan = bianDan; return this; } public TiaoBuilder setMuTong(String muTong) { this.muTong = muTong; return this; } public ToolBox build(){ return new ToolBox(this); } }
public static class TaiBuilder{ private String muGun; private String muTong;
public TaiBuilder setMuGun(String muGun) { this.muGun = muGun; return this; } public TaiBuilder setMuTong(String muTong) { this.muTong = muTong; return this; } public ToolBox build(){ return new ToolBox(this); } }
public static class DengBuilder{ public ToolBox build(){ return new ToolBox(this); } }
//省略getter方法}
具體使用
  
  
  
ToolBox oneHeShangToolBox = new ToolBox.TiaoBuilder().setMuTong("小號木桶").setBianDan("小號扁擔").build();ToolBox twoHeShangToolBox = new ToolBox.TaiBuilder().setMuTong("大號木桶").setMuGun("長號木棍").build();ToolBox threeHeShangToolBox = new ToolBox.DengBuilder().build();
建造者模式屬於創建型設計模式,它可以將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。

代理模式

爲了鼓勵多勞多得,廟裏取水開始採用積分機制,每取回來一桶水就要敲一下木魚,打一次卡。這裏就可以採用代理模式。代理分爲靜態代理和動態代理,爲了簡單起見,這裏就用靜態代理來舉例。
public class WaterableProxy implements Waterable{    /**     * 被代理的原始對象     */    private Waterable waterable;        public WaterableProxy(Waterable waterable) {        this.waterable = waterable;    }
@Override public Water getWater() { Water water = waterable.getWater(); // 增強的新功能,不管是挑水,擡水,等水,只有帶回來水,就可以 if(water != "無水"){ System.out.println("我敲一下木魚,打一次卡!"); } return water; }}
具體使用
public void doProxy(){        Waterable waterable = new Taishui();        WaterableProxy proxyWaterable = new WaterableProxy(waterable);        proxyWaterable.getWater();    }
代理模式就是代理對象具備真實對象的功能,並代替真實對象完成相應操作,並能夠在操作執行的前後,對操作進行增強處理。(通過代理訪問真實對象)

責任鏈模式

爲了升級取水工具,將小木桶升級大金桶,寺廟決定對外提供燒香拜佛,誦經禮佛等增值服務。爲了安全起見,寺廟引進了安檢機制,流程是這樣的:
  • 禁止攜帶寵物;
  • 衣着穿戴整齊;
  • 其它業障,最終解釋權歸寺廟;
  
  
  
public interface SecureFilter {    void filter(Map context);}
public class PetSecure implements SecureFilter{ @Override public void filter(Map context) { if(context.containsKey("寵物")){ throw new RuntimeException("請出去:禁止攜帶寵物進入!"); } }}
public class WearSecure implements SecureFilter{ @Override public void filter(Map context) { if(context.containsKey("光膀子")){ throw new RuntimeException("請出去:有傷風化者!"); } }}
public class OtherSecure implements SecureFilter{ @Override public void filter(Map context) { if(context.containsKey("大聲喧譁")){ throw new RuntimeException("請出去:佛門乃清淨之地!"); } }}
具體使用
  
  
  
/** * 安檢責任鏈實現 */class SecureChain implements SecureFilter{    // 注入PetSecure,WearSecure,OtherSecure等過濾器    private List<SecureFilter> secureFilterList;    /**     * 進入寺廟,進行安檢邏輯     * @param context     */    @Override    public void filter(Map context) {        // 進行安檢流程        for (SecureFilter secureFilter : secureFilterList) {            secureFilter.filter(context);        }        System.out.println("佛祖保佑,安檢通過!");    }}
流程示意圖
責任鏈模式一般和過濾器模式組合一起使用,即創建一個鏈條,經過這個鏈條處理的所有對象和數據分別進行依次加工,每個環節負責處理不同的業務,環節間彼此獨立解耦,同時可以複用。 這種設計的巧妙之處在於可以鏈式調用,不同的過濾方式可以靈活的排序和組合。 既可以使用單個過濾器進行處理,也可以直接添加一條責任鏈。

命令模式

寺廟裏的和尚除了打水工作之外,還有很多工作要做,所有的工作安排都是按照主持的指令來執行的,比如某日清晨的工作安排如下:
  1. 一號和尚做早餐;
  2. 二號和尚掃庭院;
  3. 三號和尚敲古鐘;
結構定義
  
  
  
public class Command implements Serializable {    // 做早餐,打掃,敲鐘等指令標識    private OrderTypeEnum order;    // 正向執行OR逆向回滾    private Integer direction;    // 省略get和set方法}
// 指令動作執行器,每種指令對應一個實現public interface OrderHandler { /** * 執行邏輯 * * @param callContext * @return */ PipeResult execute(CallContext callContext); /** * 支持的命令類型:做早餐,打掃,敲鐘等命令標識 * * @return */ OrderTypeEnum getOrderType();
}
// 指令類型管理器public interface PipelineCmd {
/** * 指令行定義 * * @return */ Command getCommand();
/** * 執行邏輯 * * @param pipeContext * @return */ PipeResult execute(PipeContext pipeContext);
/** * 如果可以撤消指令,則此方法應返回true ,否則返回false * * @return */ default boolean isReversible() { return true; }} // 指令執行器管理器 public interface CmdHandler { /** * 業務執行 * * @param callContext * @return */ PipeResult execute(CallContext callContext);
/** * 業務回滾(只回滾當前指令) * * @param callContext * @return */ PipeResult rollback(CallContext callContext);
/** * 全部回滾 * * @param pipeContext * @return */ PipeResult rollbackAll(PipeContext pipeContext);}
命令實現
  
  
  
public class ZhuChiCmd implements PipelineCmd {    private Command command;    private transient OrderHandler orderHandler;
public StepCmd(Command command, OrderHandler orderHandler) { this.command = command; this.orderHandler= orderHandler; }
@Override public PipeResult execute(PipeContext pipeContext) { return orderHandler.execute(new CallContext(command, pipeContext)); } // 省略get和set方法} public class Breakfast implements OrderHandler { /** * 執行邏輯 * * @param callContext * @return */ PipeResult execute(CallContext callContext){ System.out.println("做早餐啦!"); } /** * 支持的指令類型:做早餐,打掃,敲鐘等指令標識 * * @return */ OrderTypeEnum getOrderType(){ return OrderTypeEnum.BREAKFAST; }
}
public class Clean implements OrderHandler { /** * 執行邏輯 * * @param callContext * @return */ PipeResult execute(CallContext callContext){ System.out.println("打掃庭院啦!"); } /** * 支持的指令類型:做早餐,打掃,敲鐘等命令標識 * * @return */ OrderTypeEnum getOrderType(){ return OrderTypeEnum.CLEAN; }
}
public class Ring implements OrderHandler { /** * 執行邏輯 * * @param callContext * @return */ PipeResult execute(CallContext callContext){ System.out.println("敲鐘啦!"); } /** * 支持的命令類型:做早餐,打掃,敲鐘等指令標識 * * @return */ OrderTypeEnum getOrderType(){ return OrderTypeEnum.Ring; }
}
public class CmdFactory { private List<OrderHandler> orderHandlerList;
/** * 獲取指定指令條件的指令對象 * * @param command * @return */ public PipelineCmd getPipelineCmd(Command command) { for (OrderHandler orderHandler : orderHandlerList) { OrderTypeEnum orderTypeEnum = orderHandler.getOrderType(); if (orderTypeEnum.equals(command.getOrder())) { return new ZhuChiCmd(command, orderHandler); } } throw new RuntimeException("對不起主持:沒有多餘的和尚來執行新命令了!"); } /** * 獲取給定指令的回滾操作指令對象 * * @param command * @return */ public PipelineCmd getRollbackPipelineCmd(Command command) { Command rollbackCommand = getRollbackCommand(command); return getPipelineCmd(rollbackCommand); }}
具體使用
  
  
  
public class CmdHandlerImpl implements CmdHandler {    private CmdFactory cmdFactory;
@Override public PipeResult execute(CallContext callContext) { PipelineCmd pipelineCmd = cmdFactory.getPipelineCmd(callContext.getCommand()); PipeResult pipeResult = pipelineCmd.execute(callContext.getPipeContext()); return pipeResult; }
@Override public PipeResult rollback(CallContext callContext) { Command rollbackCommand = cmdFactory.getRollbackCommand(callContext.getCommand()); if (rollbackCommand == null) { return new PipeResult("不需要回滾"); } PipelineCmd pipelineCmd = cmdFactory.getPipelineCmd(rollbackCommand); if (!pipelineCmd.isReversible()) { return new PipeResult("不支持回滾"); } PipeResult pipeResult = pipelineCmd.execute(callContext.getPipeContext()); return pipeResult; }
@Override public PipeResult rollbackAll(PipeContext pipeContext) { // 命令執行備忘錄模式對象,這裏不再展開 Caretaker<Command> caretaker = pipeContext.getCaretaker(); // 拿到上一步執行命令,依次循環回滾 Command command = caretaker.pop(); while (command != null) { PipelineCmd pipelineCmd = cmdFactory.getRollbackPipelineCmd(command); if (pipelineCmd != null) { pipelineCmd.execute(pipeContext); } command = caretaker.pop(); } return new PipeResult(); }
}
命令模式將一個請求封裝爲一個對象,使發出的請求的對象和執行請求的對象分割開。這兩者之間通過命令對象進行溝通,這樣方便將命令對象進行儲存、傳遞、調用、增加與管理。命令模式可以與備忘錄模式組合使用,方便實現Undo和Redo操作。

3.3 實踐心得

設計原則

具體包含單一職責原則SRP、開閉原則OCP、里氏替換原則LSP、依賴倒置原則DIP、接口隔離原則ISP、最少知識原則LKP等很多種,其核心還是圍繞着低耦合,高複用,高內聚,易擴展,易維護展開的。

模式與原則

  1. 設計原則是指導思想,設計模式是實現手段之一;
  2. 設計原則在實際開發中並不能做到完全遵守,往往是打破一些原則,遵守一些原則,來實現設計的合理性;(成本,性能)
  3. 設計模式往往是問題解決方案的骨架,有時候可以當做開發規範和任務拆分執行落地的技術手段;
  4. 個設計模式,往往不僅僅採用一種設計原則,而是一些設計原則的整合;
  5. 設計模式不是一成不變的,可以根據問題場景,輸出新的模式;
  6. 一個複雜場景問題,有時候需要多種設計模式的組合;
  7. 學設計模式,死記硬背是沒用的,要從實踐中習得;
  8. 避免設計過度,使簡單的問題複雜化。一定要牢記簡潔原則,設計模式是爲了使設計簡單,而不是更復雜;


四、總結


本文從設計模式與編程語言的關係,設計模式與架構模式的區別,設計原則和設計模式的關係等幾個維度進行了分析和解答。 關於設計模式應該如何學習和應用的問題,給出了學習意見和實踐心得。 當然,爲了讓設計模式更加的直觀和立體,也花了大量篇幅在應用實踐案例上面,主要是通過場景化的案例,以設計模式的方式給出解決方案,其中部分場景爲了方便理解,將問題做了簡化處理,但這不影響我們去理解設計模式要解決的問題類型。 冰凍三尺非一日之寒,滴水石穿非一日之功,希望本文能夠爲你帶來幫助。

-end-


本文分享自微信公衆號 - 京東雲開發者(JDT_Developers)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章