設計模式-大話設計模式學習筆記

設計模式及使用的特性

UML示例

在這裏插入圖片描述

簡單工廠模式(SimpleFactory)

用途:實例化對象,使用單獨的類來實現創造實例,靜態方法根據參數生產不同的實例。
使用特性:繼承、多態。

策略模式(Strategy)

用途:它定義了算法家族,分別封裝起來,讓它們之間可以相互替換,此模式讓算法的變化,不會影響到算法的用戶,從而減少各種算法與使用算法之間的耦合(DPE),簡化了單元測試(策略模式比簡單工廠模式多了一個Context上下文類,該類會維護一個對父類型的引用,在該類初始化時會根據傳入的參數來初始化對應的策略對象,在該類中實現策略對象的方法,從而將算法的配置從使用者移除)。
使用特性 :繼承,多態,接口
與簡單工廠模式的比較:對應使用者來說,簡單工廠模式需要使用兩個類(Factory和父類),而策略模式只需要一個Context類,Context通過參數來生成並對應對應的類(通常爲某種算法)。
使用場景:只要需要在不同的時間應用不同的業務規則,就可以考慮使用策略模式處理這種變化的可行性。

單一職責原則(SPR)

定義:就一個類而言,應該僅有一個引起它變化的原因。
用途:降低耦合,分離UI和邏輯。

開放-封閉原則

定義:軟件實體(類、模塊、函數等等)應該可以擴展,但是不可以修改。
使用特性:對應擴展開放,對於修改封閉。
用途:在設計時,時刻考慮讓類足夠好,新的需求通過增加類來實現,通過構造抽象來隔絕修改中的變化。

依賴倒轉原則

定義:高層模塊不應該依賴底層模塊,兩個都應該依賴抽象。抽象不應該依賴細節,細節應該依賴於抽象(針對接口編程,不要對實現編程,程序中所有的依賴關係都終止於抽象類或者接口)。

里氏轉換原則

定義:子類型必須能夠替換掉他們的父類型。
用途:由於里氏轉換原則,才使得開放-封閉原則成爲可能(正由於子類型的可替換性才使得使用父類型的模塊在無需修改的情況下可以擴展)。

裝飾模式(Decorate)

定義:動態的給對象添加一些額外的職責,就功能來說,裝飾模式比生成子類更加靈活。
在這裏插入圖片描述用途:裝飾器的價值在於裝飾,他並不影響被裝飾類本身的核心功能。在一個繼承的體系中,子類通常是互斥的。比如一輛車,品牌只能要麼是奧迪、要麼是寶馬,不可能同時屬於奧迪和寶馬,而品牌也是一輛車本身的重要屬性特徵。但當你想要給汽車噴漆,換坐墊,或者更換音響時,這些功能是互相可能兼容的,並且他們的存在不會影響車的核心屬性:那就是他是一輛什麼車。這時你就可以定義一個裝飾器:噴了漆的車。不管他裝飾的車是寶馬還是奧迪,他的噴漆效果都可以實現。實際使用中可以用來裝飾日誌輸出,從而豐富Log的功能。
代碼實現

//Java版本

//基礎接口
public interface Component {
    
    public void biu();
}
//具體實現類
public class ConcretComponent implements Component {

    public void biu() {
        
        System.out.println("biubiubiu");
    }
}
//裝飾類
public class Decorator implements Component {

    public Component component;
    
    public Decorator(Component component) {
        
        this.component = component;
    }
    
    public void biu() {
        
        this.component.biu();
    }
}
//具體裝飾類
public class ConcreteDecorator extends Decorator {

    public ConcreteDecorator(Component component) {

        super(component);
    }

    public void biu() {
        
        System.out.println("ready?go!");
        this.component.biu();
    }
}

代理模式(Proxy)

定義:爲其他對象提供一種代理已以控制對這個對象的訪問。
UML圖
在這裏插入圖片描述
在上面類圖中,代理模式所涉及的角色有三個:

抽象主題角色(Subject):抽象主題類聲明瞭真實主題類和代理類的公共方法,它可以是接口、抽象類或具體類,這樣一來在使用真實主題的任何地方都可以使用代理主題。

代理主題角色(Proxy):代理主題角色內部含有對真實主題的引用,從而可以操作真實主題對象;代理主題角色負責在需要的時候創建真實主題對象;代理角色通常在將客戶端調用傳遞到真實主題之前或之後,都要執行一些其他的操作,而不是單純地將調用傳遞給真實主題對象。例如這裏的PreRequestt和PostRequest方法就是代理主題角色所執行的其他操作。

真實主題角色(RealSubject):定義了代理角色所代表的真是對象。
調用時,Client通過Proxy間接的訪問RealSubject
代碼實現

//C#版本
//抽象類
abstract class Subject
{
    public abstract void Request();
}
//真實主題角色
class RealSubject : Subject
{
    public override void Request()
    {
        //業務方法具體實現代碼
    }
}
//代理主題角色
class Proxy : Subject
{
    private RealSubject realSubject = new RealSubject(); //維持一個對真實主題對象的引用
     
    public void PreRequest() 
    {
        …...
    }
     
    public override void Request() 
    {
        PreRequest();
        realSubject.Request(); //調用真實主題對象的方法
         PostRequest();
    }
     
    public void PostRequest() 
    {
        ……
    }
}

用途: 代理模式的結構比較簡單,其核心是代理類,爲了讓客戶端能夠一致性地對待真實對象和代理對象,在代理模式中引入了抽象層。在實際開發過程中,代理類的實現比上述代碼要複雜很多,代理模式根據其目的和實現方式不同可分爲很多種類,其中常用的幾種代理模式簡要說明如下:

   (1) 遠程代理(Remote Proxy):爲一個位於不同的地址空間的對象提供一個本地的代理對象,這個不同的地址空間可以是在同一臺主機中,也可是在另一臺主機中,遠程代理又稱爲大使(Ambassador)。

   (2) 虛擬代理(Virtual Proxy):如果需要創建一個資源消耗較大的對象,先創建一個消耗相對較小的對象來表示,真實對象只在需要時纔會被真正創建。

   (3) 保護代理(Protect Proxy):控制對一個對象的訪問,可以給不同的用戶提供不同級別的使用權限。

   (4) 緩衝代理(Cache Proxy):爲某一個目標操作的結果提供臨時的存儲空間,以便多個客戶端可以共享這些結果。

   (5) 智能引用代理(Smart Reference Proxy):當一個對象被引用時,提供一些額外的操作,例如將對象被調用的次數記錄下來等。

   在這些常用的代理模式中,有些代理類的設計非常複雜,例如遠程代理類,它封裝了底層網絡通信和對遠程對象的調用,其實現較爲複雜。

工廠方法模式/工廠模式(FactoryMethod)

定義:定義一個用於創建對象的接口,讓繼承該接口的每個子類決定實例化哪一個類。工廠方法使一個類的實例化延遲到了子類。
優點工廠方法模式之所以可以解決簡單工廠的模式,是因爲它的實現把具體產品的創建推遲到子類中,此時工廠類不再負責所有產品的創建,而只是給出具體工廠必須實現的接口,這樣工廠方法模式就可以允許系統不修改工廠類邏輯的情況下來添加新產品,這樣也就克服了簡單工廠模式中缺點
UML圖
在這裏插入圖片描述
抽象產品角色(Product):定義產品的接口
具體產品角色(ConcreteProduct) :實現接口Product的具體產品類
抽象工廠角色(Creator) :聲明工廠方法(FactoryMethod),返回一個產品
真實的工廠(ConcreteCreator):實現FactoryMethod工廠方法,由客戶調用,返回一個產品的實例

原型模式(Prototype)

定義:用原型實例指定創建對象的種類,並且通過拷貝這些對象原型創建新的對象。(原型模式其實就是從一個對象再創建另一個可定製的對象,而且不需要知道任何創建的細節。)
實現方法: 1、實現克隆操作,在 JAVA 繼承 Cloneable,重寫 clone(),在 .NET 中可以使用 Object 類(需要繼承ICloneable接口)的 MemberwiseClone() 方法來實現對象的淺拷貝(通過對引用類型的類實現ICloneable接口的MemberwiseClone方法也能實現深拷貝,但是要注意深入的層次和循環引用的問題)或通過序列化的方式來實現深拷貝。 2、原型模式同樣用於隔離類對象的使用者和具體類型(易變類)之間的耦合關係,它同樣要求這些"易變類"擁有穩定的接口。

使用場景

 1.在需要一個類的大量對象的時候,使用原型模式是最佳選擇,因爲原型模式是在內存中對這個對象進行拷貝,要比直接new這個對象性能要好很多,在這種情況下,需要的對象越多,原型模式體現出的優點越明顯。
 2.如果一個對象的初始化需要很多其他對象的數據準備或其他資源的繁瑣計算,那麼可以使用原型模式。
 3.當需要一個對象的大量公共信息,少量字段進行個性化設置的時候,也可以使用原型模式拷貝出現有對象的副本進行加工處理。

模板方法模式(TemplateMethod)

定義:定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。
作用:模板方法使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
UML圖
在這裏插入圖片描述

迪米特法則/最少知識原則

定義:如果兩個類不必彼此直接通信,那麼這兩個類就不應當發生直接的相互作用。如果其中一個需要調用另一個類的某一個方法的話,可以通過第三者轉發這個調用。
迪米特法則首先強調的前提使在類的結構設計上,每一個類都應當儘量降低成員的訪問權限。也就是說,一個類包裝好自己的private狀態,不需要讓別的類知道的字段或行爲就不要公開,需要公開的字段,通常用屬性來體現(封裝)。

外觀模式(Facade)

定義 :爲子系統的一組接口提供一個一致的界面,此模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。
UML圖
在這裏插入圖片描述使用場景
1.在設計的初期階段,應該有意識地將不同的兩個層分離,比如經典的三層架構。
2.在開發階段,子系統往往因爲不斷的重構演化而變地越來越複雜,增加外觀 Facade 可以提供一個簡單的接口,減少依賴。
3.在維護一個遺留的大型系統時,增加一個外觀 Facade 類,讓 新系統與Facade對象交互,Facade與遺留代碼加護所有複雜的工作。

建造者模式(Builder)

定義 :將一個複雜的構建與其表示相分離,使得同樣的構建過程可以創建不同的表示。

UML圖
在這裏插入圖片描述作用:主要是用於創建一些複雜的對象,這些對下你個內部構建間的順序通常是穩定的,但是對象內部的構建通常面臨着複雜的變化。

觀察者模式(Observer)

定義 :觀察這模式定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象,這個主題對象在狀態發生變化時,會通知所有觀察者對象,讓它們能夠自動更新自己。
使用場景:當一個對象的改變需要同時改變其他對象而且它不知道具體有多少對象有待改變的時候。
一個抽象模型有兩個方面,其中一個方面依賴另一個方面。
觀察這模式所作的工作就是接觸耦合,讓耦合的雙方都依賴於抽象,而不是依賴於具體,從使得各自的變化都不會影響另一邊的變化。
UML圖
在這裏插入圖片描述

抽象工廠模式(Abstract Factory)

定義 :提供一個創建一系列相關或相互依賴對象的接口,而無需指定它們的具體的類。
UML圖
在這裏插入圖片描述優點 :當一個產品族中的多個對象被設計成一起工作時,它能保證客戶端始終只使用同一個產品族中的對象。

缺點 :擴展非常,要增加一個系列的某一產品,既要在抽象的 Creator 里加代碼,又要在具體的裏面加代碼。

狀態模式(State)

定義 :當一個對象的內在狀態改變時允許改變其行爲,這個對象看起來像是改變了其類。
使用場景 :狀態模式主要解決的時當控制一個對象狀態轉換的條件表達式過於複雜時的情況。把狀態的判定邏輯轉移到表示不同狀態的一系列類中,可以把複雜的判斷邏輯簡化。‘
UML圖
在這裏插入圖片描述

適配器模式(Adapter)

定義:將一個類的接口轉換成客戶希望的另一個接口。Adapter模式 使得原本由於接口不兼容而不能一起工作的那些類可以一起工作。
UML圖
在這裏插入圖片描述

備忘錄模式(Memento)

定義:在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態。這樣以後就可以將該對象恢復到保存之前的狀態。
使用場景 :備忘錄模式適用於功能比較複雜,但是需要維護和記錄屬性歷史的類,或者需要保存的屬性只是衆多屬性中的一小部分時,Originator可以根據保存的Memento信息還原到前一狀態。
UML圖
在這裏插入圖片描述
優點: 1、給用戶提供了一種可以恢復狀態的機制,可以使用戶能夠比較方便地回到某個歷史的狀態。 2、實現了信息的封裝,使得用戶不需要關心狀態的保存細節。
缺點:消耗資源。如果類的成員變量過多,勢必會佔用比較大的資源,而且每一次保存都會消耗一定的內存。

組合模式(Composite)

定義:將對象組合成樹形結構以表示 ‘部分-整體’ 的層次結構。組合模式使得用戶對單個對象和組合對象的使用具有一致性。
使用場景:當發現需求中是體現部分於整體層次的結構時,以及希望用戶可以忽略組合對象與單個對象的不同,統一得使用組合結構中的所有對象時,就應該考慮組合模式。
優點: 1、高層模塊調用簡單。 2、節點自由增加。
缺點:在使用組合模式時,其葉子和樹枝的聲明都是實現類,而不是接口,違反了依賴倒置原則。
UML圖
在這裏插入圖片描述

迭代器模式(Iterator)

定義:提供一種方法順序訪問一個聚合對象中的各個元素,而又不暴露該對象的內部表示。
使用場景:當需要訪問一個聚集對象,而且不管這些對象是什麼都需要遍歷的時候,需要考慮用迭代器模式。爲遍歷不同的聚集結構提供如開始、下一個、是否結束、當前哪一項等統一的接口。(C#中的foreach提供了迭代器模式的實現)
UML圖
在這裏插入圖片描述
.NET的迭代器實現:IEnumerator、IEnumerable接口

單例模式(Singleton)

定義:保證一個類僅有一個實例,並且提供一個訪問它的全局訪問點。
關鍵:構造函數是私有的,只有一個訪問點且訪問點是靜態的。
注意:多線程開發時對訪問點加鎖。
優點
1、在內存裏只有一個實例,減少了內存的開銷,尤其是頻繁的創建和銷燬實例(比如管理學院首頁頁面緩存)。
2、避免對資源的多重佔用(比如寫文件操作)。

缺點:沒有接口,不能繼承,與單一職責原則衝突,一個類應該只關心內部邏輯,而不關心外面怎麼樣來實例化。
普通單利模式

        private static Singleton instance;
        private Singleton() { }
        public static Singleton GetInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }

線程安全的單利模式代碼

        private static Singleton instance;
        private static readonly object syncRoot = new object();
        private Singleton() { }
        public static Singleton GetInstance() {
            if (instance == null) {
                lock (syncRoot) {
                    if (instance == null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }

靜態初始化的單利模式

        private static readonly Singleton instance=new Singleton();
        private Singleton() { }
        public static Singleton GetInstance() {
            return instance;
        }
    }

橋接模式(Bridge)

定義:將抽象部分與它的實現部分分離,使它們可以獨立地變化。
合成/聚合複用原則:儘量使用合成/聚合,儘量不要使用類繼承。

在這裏插入圖片描述
合成/聚合複用原則的優點:優先使用合成/聚合複用原則將有助於保持每個類被封裝,並被集中在單個任務上,這樣類和類繼承層次會保持較小的規模,並且不太可能增長成爲不可控制的龐然大物。
UML圖
在這裏插入圖片描述使用場景:實現系統可能有多角度分類,每一種分類都有可能變化,那麼就把這種多角度分離出來讓它們獨立變化,減少它們之間的耦合。

命令模式(Command)

定義:將一個請求封裝爲一個對象,從而可以使用不同的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支持可撤銷的操作。
UML圖
在這裏插入圖片描述
優點
1、能夠較容易的設計一個命令隊列。
2、在需要的情況下,可以較容易的將命令記入日誌。
3、允許接收請求的一方決定是否要否決請求。
4、可以容易的實現對請求的撤銷和重做。
5、由於加入新的具體命令類不影響其他的類,依次增加新的具體命令類很容易。
6、把請求操作的對象與操作的執行對象分割。

職責鏈模式(Chain of Responsibility)

定義:使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。將這個對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止。
UML圖
在這裏插入圖片描述優點: 1、降低耦合度。它將請求的發送者和接收者解耦。 2、簡化了對象。使得對象不需要知道鏈的結構。 3、增強給對象指派職責的靈活性。通過改變鏈內的成員或者調動它們的次序,允許動態地新增或者刪除責任。 4、增加新的請求處理類很方便。

缺點: 1、不能保證請求一定被接收。 2、系統性能將受到一定影響,而且在進行代碼調試時不太方便,可能會造成循環調用。 3、可能不容易觀察運行時的特徵,有礙於除錯。

中介者模式(Mediator)

定義:用一箇中介對象來封裝一系列的對象交互。中介者使各對象不需要顯式的相互引用,從而使耦合鬆散,而且可以獨立的改變他們的交互。
UML圖
在這裏插入圖片描述何時使用:多個類相互耦合,形成了網狀結構。
優點: 1、降低了類的複雜度,將一對多轉化成了一對一。 2、各個類之間的解耦。 3、符合迪米特原則。
缺點:中介者會變地龐大複雜而難以維護。

享元模式(Flyweight)

定義:運用共享技術有效的支持大量細粒度的對象。
UML圖
在這裏插入圖片描述
應用場景: 1、系統中有大量對象。 2、這些對象消耗大量內存。 3、這些對象的狀態大部分可以外部化。 4、這些對象可以按照內蘊狀態分爲很多組,當把外蘊對象從對象中剔除出來時,每一組對象都可以用一個對象來代替。 5、系統不依賴於這些對象身份,這些對象是不可分辨的。
特定:用 HashMap 存儲這些對象。

優點:大大減少對象的創建,降低系統的內存,使效率提高。

缺點:提高了系統的複雜度,需要分離出外部狀態和內部狀態,而且外部狀態具有固有化的性質,不應該隨着內部狀態的變化而變化,否則會造成系統的混亂。

解釋器模式(interpreter)

定義:給定一個語言,定義它的文法的一種表示,並定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。
優點: 1、可擴展性比較好,靈活。 2、增加了新的解釋表達式的方式。 3、易於實現簡單文法。
缺點: 1、可利用場景比較少。 2、對於複雜的文法比較難維護。 3、解釋器模式會引起類膨脹。 4、解釋器模式採用遞歸調用方法。
使用場景: 1、可以將一個需要解釋執行的語言中的句子表示爲一個抽象語法樹。 2、一些重複出現的問題可以用一種簡單的語言來進行表達。 3、一個簡單語法需要解釋的場景。

訪問者模式(Vistor)

定義:表示一個作用於某對象結構種的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用於這些元素的新操作。

優點: 1、符合單一職責原則。 2、優秀的擴展性。 3、靈活性。

缺點: 1、具體元素對訪問者公佈細節,違反了迪米特原則。 2、具體元素變更比較困難。 3、違反了依賴倒置原則,依賴了具體類,沒有依賴抽象。

使用場景: 1、對象結構中對象對應的類很少改變,但經常需要在此對象結構上定義新的操作。 2、需要對一個對象結構中的對象進行很多不同的並且不相關的操作,而需要避免讓這些操作"污染"這些對象的類,也不希望在增加新操作時修改這些類。訪問者可以對功能進行統一,可以做報表、UI、攔截器與過濾器。

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