23種設計模式,你學廢了嘛?

来源:https://www.cnblogs.com/88223100/archive/2022/12/22/Have-you-learned-23-design-models.html
-Advertisement-
Play Games

23種經典設計模式共分為3種類型,分別是創建型、結構型和行為型。 今天,我們把這3種類型分成3個對應的小模塊,逐一帶你回顧一下每一種設計模式的原理、實現、設計意圖和應用場景。 還是那句話,如果你看了之後,感覺都有印象,那就說明學得還不錯;如果還能在腦子裡形成自己的知識架構,閉上眼睛都能回憶上來,... ...


 

 

23種經典設計模式共分為3種類型,分別是創建型、結構型和行為型。

今天,我們把這3種類型分成3個對應的小模塊,逐一帶你回顧一下每一種設計模式的原理、實現、設計意圖和應用場景。

還是那句話,如果你看了之後,感覺都有印象,那就說明學得還不錯;如果還能在腦子裡形成自己的知識架構,閉上眼睛都能回憶上來,那說明你學得很好;

如果能有自己的理解,並且在項目開發中,開始思考代碼質量問題,開始用已經學過的設計模式來解決代碼問題,那說明你已經掌握這些內容的精髓。

一、創建型設計模式

創建型設計模式包括:單例模式、工廠模式、建造者模式、原型模式。它主要解決對象的創建問題,封裝複雜的創建過程,解耦對象的創建代碼和使用代碼。

1.單例模式

單例模式用來創建全局唯一的對象。一個類只允許創建一個對象(或者叫實例),那這個類就是一個單例類,這種設計模式就叫作單例模式。單例有幾種經典的實現方式,它們分別是:餓漢式、懶漢式、雙重檢測、靜態內部類、枚舉。

儘管單例是一個很常用的設計模式,在實際的開發中,我們也確實經常用到它,但是,有些人認為單例是一種反模式(anti-pattern),並不推薦使用,主要的理由有以下幾點:

- 單例對OOP特性的支持不友好

- 單例會隱藏類之間的依賴關係

- 單例對代碼的擴展性不友好

- 單例對代碼的可測試性不友好

- 單例不支持有參數的構造函數

那有什麼替代單例的解決方案呢?如果要完全解決這些問題,我們可能要從根上尋找其他方式來實現全局唯一類。比如,通過工廠模式、IOC容器來保證全局唯一性。

有人把單例當作反模式,主張杜絕在項目中使用。我個人覺得這有點極端。模式本身沒有對錯,關鍵看你怎麼用。如果單例類並沒有後續擴展的需求,並且不依賴外部系統,那設計成單例類就沒有太大問題。

對於一些全局類,我們在其他地方new的話,還要在類之間傳來傳去,不如直接做成單例類,使用起來簡潔方便。

除此之外,我們還講到了進程唯一單例、線程唯一單例、集群唯一單例、多例等擴展知識點,這一部分在實際的開發中並不會被用到,但是可以擴展你的思路、鍛煉你的邏輯思維。這裡我就不帶你回顧了,你可以自己回憶一下。

2.工廠模式

工廠模式包括簡單工廠、工廠方法、抽象工廠這3種細分模式。其中,簡單工廠和工廠方法比較常用,抽象工廠的應用場景比較特殊,所以很少用到,不是我們學習的重點。

工廠模式用來創建不同但是相關類型的對象(繼承同一父類或者介面的一組子類),由給定的參數來決定創建哪種類型的對象。實際上,如果創建對象的邏輯並不複雜,那我們直接通過new來創建對象就可以了,不需要使用工廠模式。

當創建邏輯比較複雜,是一個“大工程”的時候,我們就考慮使用工廠模式,封裝對象的創建過程,將對象的創建和使用相分離。

當每個對象的創建邏輯都比較簡單的時候,我推薦使用簡單工廠模式,將多個對象的創建邏輯放到一個工廠類中。

當每個對象的創建邏輯都比較複雜的時候,為了避免設計一個過於龐大的工廠類,我們推薦使用工廠方法模式,將創建邏輯拆分得更細,每個對象的創建邏輯獨立到各自的工廠類中。

詳細點說,工廠模式的作用有下麵4個,這也是判斷要不要使用工廠模式最本質的參考標準。

- 封裝變化:創建邏輯有可能變化,封裝成工廠類之後,創建邏輯的變更對調用者透明。

- 代碼復用:創建代碼抽離到獨立的工廠類之後可以復用。

- 隔離複雜性:封裝複雜的創建邏輯,調用者無需瞭解如何創建對象。

- 控制複雜度:將創建代碼抽離出來,讓原本的函數或類職責更單一,代碼更簡潔。

除此之外,我們還講了工廠模式一個非常經典的應用場景:依賴註入框架,比如Spring IOC、Google Guice,它用來集中創建、組裝、管理對象,跟具體業務代碼解耦,讓程式員聚焦在業務代碼的開發上。DI框架已經成為了我們平時開發的必備框架,在專欄中,我還帶你實現了一個簡單的DI框架,你可以再回過頭去看看。

3.建造者模式

建造者模式用來創建複雜對象,可以通過設置不同的可選參數,“定製化”地創建不同的對象。建造者模式的原理和實現比較簡單,重點是掌握應用場景,避免過度使用。

如果一個類中有很多屬性,為了避免構造函數的參數列表過長,影響代碼的可讀性和易用性,我們可以通過構造函數配合set()方法來解決。但是,如果存在下麵情況中的任意一種,我們就要考慮使用建造者模式了。

- 我們把類的必填屬性放到構造函數中,強制創建對象的時候就設置。如果必填的屬性有很多,把這些必填屬性都放到構造函數中設置,那構造函數就又會出現參數列表很長的問題。如果我們把必填屬性通過set()方法設置,那校驗這些必填屬性是否已經填寫的邏輯就無處安放了。

- 如果類的屬性之間有一定的依賴關係或者約束條件,我們繼續使用構造函數配合set()方法的設計思路,那這些依賴關係或約束條件的校驗邏輯就無處安放了。

- 如果我們希望創建不可變對象,也就是說,對象在創建好之後,就不能再修改內部的屬性值,要實現這個功能,我們就不能在類中暴露set()方法。構造函數配合set()方法來設置屬性值的方式就不適用了。

4.原型模式

如果對象的創建成本比較大,而同一個類的不同對象之間差別不大(大部分欄位都相同),在這種情況下,我們可以利用對已有對象(原型)進行複製(或者叫拷貝)的方式,來創建新對象,以達到節省創建時間的目的。這種基於原型來創建對象的方式就叫作原型模式。

原型模式有兩種實現方法,深拷貝和淺拷貝。淺拷貝只會複製對象中基本數據類型數據和引用對象的記憶體地址,不會遞歸地複製引用對象,以及引用對象的引用對象……而深拷貝得到的是一份完完全全獨立的對象。所以,深拷貝比起淺拷貝來說,更加耗時,更加耗記憶體空間。

如果要拷貝的對象是不可變對象,淺拷貝共用不可變對象是沒問題的,但對於可變對象來說,淺拷貝得到的對象和原始對象會共用部分數據,就有可能出現數據被修改的風險,也就變得複雜多了。操作非常耗時的情況下,我們比較推薦使用淺拷貝,否則,沒有充分的理由,不要為了一點點的性能提升而使用淺拷貝。

二、結構型設計模式

結構型模式主要總結了一些類或對象組合在一起的經典結構,這些經典的結構可以解決特定應用場景的問題。結構型模式包括:代理模式、橋接模式、裝飾器模式、適配器模式、門面模式、組合模式、享元模式。

1.代理模式

代理模式在不改變原始類介面的條件下,為原始類定義一個代理類,主要目的是控制訪問,而非加強功能,這是它跟裝飾器模式最大的不同。

一般情況下,我們讓代理類和原始類實現同樣的介面。但是,如果原始類並沒有定義介面,並且原始類代碼並不是我們開發維護的。在這種情況下,我們可以通過讓代理類繼承原始類的方法來實現代理模式。

靜態代理需要針對每個類都創建一個代理類,並且每個代理類中的代碼都有點像模板式的“重覆”代碼,增加了維護成本和開發成本。對於靜態代理存在的問題,我們可以通過動態代理來解決。

我們不事先為每個原始類編寫代理類,而是在運行的時候動態地創建原始類對應的代理類,然後在系統中用代理類替換掉原始類。

代理模式常用在業務系統中開發一些非功能性需求,比如:監控、統計、鑒權、限流、事務、冪等、日誌。我們將這些附加功能與業務功能解耦,放到代理類統一處理,讓程式員只需要關註業務方面的開發。除此之外,代理模式還可以用在RPC、緩存等應用場景中。

2.橋接模式

橋接模式的代碼實現非常簡單,但是理解起來稍微有點難度,並且應用場景也比較局限,所以,相對來說,橋接模式在實際的項目中並沒有那麼常用,你只需要簡單瞭解,見到能認識就可以了,並不是我們學習的重點。

橋接模式有兩種理解方式。第一種理解方式是“將抽象和實現解耦,讓它們能獨立開發”。這種理解方式比較特別,應用場景也不多。

另一種理解方式更加簡單,等同於“組合優於繼承”設計原則,這種理解方式更加通用,應用場景比較多。不管是哪種理解方式,它們的代碼結構都是相同的,都是一種類之間的組合關係。

對於第一種理解方式,弄懂定義中“抽象”和“實現”兩個概念,是理解它的關鍵。定義中的“抽象”,指的並非“抽象類”或“介面”,而是被抽象出來的一套“類庫”,它只包含骨架代碼,真正的業務邏輯需要委派給定義中的“實現”來完成。

而定義中的“實現”,也並非“介面的實現類”,而是的一套獨立的“類庫”。“抽象”和“實現”獨立開發,通過對象之間的組合關係組裝在一起。

3.裝飾器模式

裝飾器模式主要解決繼承關係過於複雜的問題,通過組合來替代繼承,給原始類添加增強功能。這也是判斷是否該用裝飾器模式的一個重要的依據。

除此之外,裝飾器模式還有一個特點,那就是可以對原始類嵌套使用多個裝飾器。為了滿足這樣的需求,在設計的時候,裝飾器類需要跟原始類繼承相同的抽象類或者介面。

4.適配器模式

代理模式、裝飾器模式提供的都是跟原始類相同的介面,而適配器提供跟原始類不同的介面。適配器模式是用來做適配的,它將不相容的介面轉換為可相容的介面,讓原本由於介面不相容而不能一起工作的類可以一起工作。

適配器模式有兩種實現方式:類適配器和對象適配器。其中,類適配器使用繼承關係來實現,對象適配器使用組合關係來實現。

適配器模式是一種事後的補救策略,用來補救設計上的缺陷。應用這種模式算是“無奈之舉”。如果在設計初期,我們就能規避介面不相容的問題,那這種模式就無用武之地了。在實際的開發中,什麼情況下才會出現介面不相容呢?我總結下了下麵這5種場景:

- 封裝有缺陷的介面設計

- 統一多個類的介面設計

- 替換依賴的外部系統

- 相容老版本介面

- 適配不同格式的數據

5.門面模式

門面模式原理、實現都非常簡單,應用場景比較明確。它通過封裝細粒度的介面,提供組合各個細粒度介面的高層次介面,來提高介面的易用性,或者解決性能、分散式事務等問題。

6.組合模式

組合模式跟我們之前講的面向對象設計中的“組合關係(通過組合來組裝兩個類)”,完全是兩碼事。這裡講的“組合模式”,主要是用來處理樹形結構數據。

正因為其應用場景的特殊性,數據必須能表示成樹形結構,這也導致了這種模式在實際的項目開發中並不那麼常用。但是,一旦數據滿足樹形結構,應用這種模式就能發揮很大的作用,能讓代碼變得非常簡潔。

組合模式的設計思路,與其說是一種設計模式,倒不如說是對業務場景的一種數據結構和演算法的抽象。其中,數據可以表示成樹這種數據結構,業務需求可以通過在樹上的遞歸遍歷演算法來實現。

組合模式,將一組對象組織成樹形結構,將單個對象和組合對象都看作樹中的節點,以統一處理邏輯,並且它利用樹形結構的特點,遞歸地處理每個子樹,依次簡化代碼實現。

7.享元模式

所謂“享元”,顧名思義就是被共用的單元。享元模式的意圖是復用對象,節省記憶體,前提是享元對象是不可變對象。

具體來講,當一個系統中存在大量重覆對象的時候,我們就可以利用享元模式,將對象設計成享元,在記憶體中只保留一份實例,供多處代碼引用,這樣可以減少記憶體中對象的數量,以起到節省記憶體的目的。

實際上,不僅僅相同對象可以設計成享元,對於相似對象,我們也可以將這些對象中相同的部分(欄位),提取出來設計成享元,讓這些大量相似對象引用這些享元。

三、行為型設計模式

我們知道,創建型設計模式主要解決“對象的創建”問題,結構型設計模式主要解決“類或對象的組合”問題,那行為型設計模式主要解決的就是“類或對象之間的交互”問題。行為型模式比較多,有11種,它們分別是:觀察者模式、模板模式、策略模式、職責鏈模式、迭代器模式、狀態模式、訪問者模式、備忘錄模式、命令模式、解釋器模式、中介模式。

1.觀察者模式

觀察者模式將觀察者和被觀察者代碼解耦。觀察者模式的應用場景非常廣泛,小到代碼層面的解耦,大到架構層面的系統解耦,再或者一些產品的設計思路,都有這種模式的影子,比如,郵件訂閱、RSS Feeds,本質上都是觀察者模式。

不同的應用場景和需求下,這個模式也有截然不同的實現方式:有同步阻塞的實現方式,也有非同步非阻塞的實現方式;有進程內的實現方式,也有跨進程的實現方式。

同步阻塞是最經典的實現方式,主要是為了代碼解耦;非同步非阻塞除了能實現代碼解耦之外,還能提高代碼的執行效率;進程間的觀察者模式解耦更加徹底,一般是基於消息隊列來實現,用來實現不同進程間的被觀察者和觀察者之間的交互。

框架的作用有隱藏實現細節,降低開發難度,實現代碼復用,解耦業務與非業務代碼,讓程式員聚焦業務開發。針對非同步非阻塞觀察者模式,我們也可以將它抽象成EventBus框架來達到這樣的效果。

EventBus翻譯為“事件匯流排”,它提供了實現觀察者模式的骨架代碼。我們可以基於此框架非常容易地在自己的業務場景中實現觀察者模式,不需要從零開始開發。

2.模板模式

模板方法模式在一個方法中定義一個演算法骨架,並將某些步驟推遲到子類中實現。模板方法模式可以讓子類在不改變演算法整體結構的情況下,重新定義演算法中的某些步驟。這裡的“演算法”,我們可以理解為廣義上的“業務邏輯”,並不特指數據結構和演算法中的“演算法”。

這裡的演算法骨架就是“模板”,包含演算法骨架的方法就是“模板方法”,這也是模板方法模式名字的由來。

模板模式有兩大作用:復用和擴展。其中復用指的是,所有的子類可以復用父類中提供的模板方法的代碼。擴展指的是,框架通過模板模式提供功能擴展點,讓框架用戶可以在不修改框架源碼的情況下,基於擴展點定製化框架的功能。

除此之外,我們還講到回調。它跟模板模式具有相同的作用:代碼復用和擴展。在一些框架、類庫、組件等的設計中經常會用到,比如JdbcTemplate就是用了回調。

相對於普通的函數調用,回調是一種雙向調用關係。A類事先註冊某個函數F到B類,A類在調用B類的P函數的時候,B類反過來調用A類註冊給它的F函數。這裡的F函數就是“回調函數”。A調用B,B反過來又調用A,這種調用機制就叫作“回調”。

回調可以細分為同步回調和非同步回調。從應用場景上來看,同步回調看起來更像模板模式,非同步回調看起來更像觀察者模式。回調跟模板模式的區別,更多的是在代碼實現上,而非應用場景上。回調基於組合關係來實現,模板模式基於繼承關係來實現。回調比模板模式更加靈活。

3.策略模式

策略模式定義一組演算法類,將每個演算法分別封裝起來,讓它們可以互相替換。策略模式可以使演算法的變化獨立於使用它們的客戶端(這裡的客戶端代指使用演算法的代碼)。策略模式用來解耦策略的定義、創建、使用。實際上,一個完整的策略模式就是由這三個部分組成的。

策略類的定義比較簡單,包含一個策略介面和一組實現這個介面的策略類。策略的創建由工廠類來完成,封裝策略創建的細節。

策略模式包含一組策略可選,客戶端代碼選擇使用哪個策略,有兩種確定方法:編譯時靜態確定和運行時動態確定。其中,“運行時動態確定”才是策略模式最典型的應用場景。

在實際的項目開發中,策略模式也比較常用。最常見的應用場景是,利用它來避免冗長的if-else或switch分支判斷。不過,它的作用還不止如此。它也可以像模板模式那樣,提供框架的擴展點等等。

實際上,策略模式主要的作用還是解耦策略的定義、創建和使用,控制代碼的複雜度,讓每個部分都不至於過於複雜、代碼量過多。除此之外,對於複雜代碼來說,策略模式還能讓其滿足開閉原則,添加新策略的時候,最小化、集中化代碼改動,減少引入bug的風險。

4.職責鏈模式

在職責鏈模式中,多個處理器依次處理同一個請求。一個請求先經過A處理器處理,然後再把請求傳遞給B處理器,B處理器處理完後再傳遞給C處理器,以此類推,形成一個鏈條。鏈條上的每個處理器各自承擔各自的處理職責,所以叫作職責鏈模式。

在GoF的定義中,一旦某個處理器能處理這個請求,就不會繼續將請求傳遞給後續的處理器了。當然,在實際的開發中,也存在對這個模式的變體,那就是請求不會中途終止傳遞,而是會被所有的處理器都處理一遍。

職責鏈模式常用在框架開發中,用來實現過濾器、攔截器功能,讓框架的使用者在不需要修改框架源碼的情況下,添加新的過濾、攔截功能。這也體現了之前講到的對擴展開放、對修改關閉的設計原則。

5.迭代器模式

迭代器模式也叫游標模式,它用來遍歷集合對象。這裡說的“集合對象”,我們也可以叫“容器”“聚合對象”,實際上就是包含一組對象的對象,比如,數組、鏈表、樹、圖、跳錶。

迭代器模式主要作用是解耦容器代碼和遍歷代碼。大部分編程語言都提供了現成的迭代器可以使用,我們不需要從零開始開發。

遍歷集合一般有三種方式:for迴圈、foreach迴圈、迭代器遍歷。後兩種本質上屬於一種,都可以看作迭代器遍歷。相對於for迴圈遍歷,利用迭代器來遍歷有3個優勢:

- 迭代器模式封裝集合內部的複雜數據結構,開發者不需要瞭解如何遍歷,直接使用容器提供的迭代器即可;

- 迭代器模式將集合對象的遍歷操作從集合類中拆分出來,放到迭代器類中,讓兩者的職責更加單一;

- 迭代器模式讓添加新的遍歷演算法更加容易,更符合開閉原則。除此之外,因為迭代器都實現自相同的介面,在開發中,基於介面而非實現編程,替換迭代器也變得更加容易。

在通過迭代器來遍歷集合元素的同時,增加或者刪除集合中的元素,有可能會導致某個元素被重覆遍歷或遍歷不到。針對這個問題,有兩種比較乾脆利索的解決方案,來避免出現這種不可預期的運行結果。

一種是遍歷的時候不允許增刪元素,另一種是增刪元素之後讓遍歷報錯。第一種解決方案比較難實現,因為很難確定迭代器使用結束的時間點。第二種解決方案更加合理,Java語言就是採用的這種解決方案。增刪元素之後,我們選擇fail-fast解決方式,讓遍歷操作直接拋出運行時異常。

6.狀態模式

狀態模式一般用來實現狀態機,而狀態機常用在游戲、工作流引擎等系統開發中。狀態機又叫有限狀態機,它由3個部分組成:狀態、事件、動作。

其中,事件也稱為轉移條件。事件觸髮狀態的轉移及動作的執行。不過,動作不是必須的,也可能只轉移狀態,不執行任何動作。

針對狀態機,我們總結了三種實現方式。

第一種實現方式叫分支邏輯法。利用if-else或者switch-case分支邏輯,參照狀態轉移圖,將每一個狀態轉移原模原樣地直譯成代碼。對於簡單的狀態機來說,這種實現方式最簡單、最直接,是首選。

第二種實現方式叫查表法。對於狀態很多、狀態轉移比較複雜的狀態機來說,查表法比較合適。通過二維數組來表示狀態轉移圖,能極大地提高代碼的可讀性和可維護性。

第三種實現方式就是利用狀態模式。對於狀態並不多、狀態轉移也比較簡單,但事件觸發執行的動作包含的業務邏輯可能比較複雜的狀態機來說,我們首選這種實現方式。

7.訪問者模式

訪問者模式允許一個或者多個操作應用到一組對象上,設計意圖是解耦操作和對象本身,保持類職責單一、滿足開閉原則以及應對代碼的複雜性。

對於訪問者模式,學習的主要難點在代碼實現。而代碼實現比較複雜的主要原因是,函數重載在大部分面向對象編程語言中是靜態綁定的。

也就是說,調用類的哪個重載函數,是在編譯期間,由參數的聲明類型決定的,而非運行時,根據參數的實際類型決定的。除此之外,我們還講到Double Disptach。如果某種語言支持Double Dispatch,那就不需要訪問者模式了。

正是因為代碼實現難理解,所以,在項目中應用這種模式,會導致代碼的可讀性比較差。如果你的同事不瞭解這種設計模式,可能就會讀不懂、維護不了你寫的代碼。所以,除非不得已,不要使用這種模式。

8.備忘錄模式

備忘錄模式也叫快照模式,具體來說,就是在不違背封裝原則的前提下,捕獲一個對象的內部狀態,併在該對象之外保存這個狀態,以便之後恢復對象為先前的狀態。

這個模式的定義表達了兩部分內容:一部分是,存儲副本以便後期恢復;另一部分是,要在不違背封裝原則的前提下,進行對象的備份和恢復。

備忘錄模式的應用場景也比較明確和有限,主要用來防丟失、撤銷、恢復等。它跟平時我們常說的“備份”很相似。兩者的主要區別在於,備忘錄模式更側重於代碼的設計和實現,備份更側重架構設計或產品設計。

對於大對象的備份來說,備份占用的存儲空間會比較大,備份和恢復的耗時會比較長。針對這個問題,不同的業務場景有不同的處理方式。

比如,只備份必要的恢覆信息,結合最新的數據來恢復;再比如,全量備份和增量備份相結合,低頻全量備份,高頻增量備份,兩者結合來做恢復。

9.命令模式

命令模式在平時工作中並不常用,你稍微瞭解一下就可以。

落實到編碼實現,命令模式用到最核心的實現手段,就是將函數封裝成對象。我們知道,在大部分編程語言中,函數是沒法作為參數傳遞給其他函數的,也沒法賦值給變數。藉助命令模式,我們將函數封裝成對象,這樣就可以實現把函數像對象一樣使用。

命令模式的主要作用和應用場景,是用來控制命令的執行,比如,非同步、延遲、排隊執行命令、撤銷重做命令、存儲命令、給命令記錄日誌等,這才是命令模式能發揮獨一無二作用的地方。

10.解釋器模式

解釋器模式為某個語言定義它的語法(或者叫文法)表示,並定義一個解釋器用來處理這個語法。實際上,這裡的“語言”不僅僅指我們平時說的中、英、日、法等各種語言。

從廣義上來講,只要是能承載信息的載體,我們都可以稱之為“語言”,比如,古代的結繩記事、盲文、啞語、摩斯密碼等。

要想瞭解“語言”要表達的信息,我們就必須定義相應的語法規則。這樣,書寫者就可以根據語法規則來書寫“句子”(專業點的叫法應該是“表達式”),閱讀者根據語法規則來閱讀“句子”,這樣才能做到信息的正確傳遞。

而我們要講的解釋器模式,其實就是用來實現根據語法規則解讀“句子”的解釋器。

解釋器模式的代碼實現比較靈活,沒有固定的模板。我們前面說過,應用設計模式主要是應對代碼的複雜性,解釋器模式也不例外。它的代碼實現的核心思想,就是將語法解析的工作拆分到各個小類中,以此來避免大而全的解析類。

一般的做法是,將語法規則拆分一些小的獨立的單元,然後對每個單元進行解析,最終合併為對整個語法規則的解析。

11.中介模式

中介模式的設計思想跟中間層很像,通過引入中介這個中間層,將一組對象之間的交互關係(或者說依賴關係)從多對多(網狀關係)轉換為一對多(星狀關係)。原來一個對象要跟n個對象交互,現在只需要跟一個中介對象交互,從而最小化對象之間的交互關係,降低了代碼的複雜度,提高了代碼的可讀性和可維護性。

觀察者模式和中介模式都是為了實現參與者之間的解耦,簡化交互關係。兩者的不同在於應用場景上。在觀察者模式的應用場景中,參與者之間的交互比較有條理,一般都是單向的,一個參與者只有一個身份,要麼是觀察者,要麼是被觀察者。

而在中介模式的應用場景中,參與者之間的交互關係錯綜複雜,既可以是消息的發送者、也可以同時是消息的接收者。

如果有收穫,歡迎你收藏這篇文章,反覆閱讀,並把它分享給你的朋友。

 

作者:王爭

本文來自博客園,作者:古道輕風,轉載請註明原文鏈接:https://www.cnblogs.com/88223100/p/Have-you-learned-23-design-models.html


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

-Advertisement-
Play Games
更多相關文章
  • 案例介紹 歡迎來的我的小院,我是霍大俠,恭喜你今天又要進步一點點了!我們來用JavaScript編程實戰案例,做一個滑鼠愛心特效。滑鼠在頁面移動時會出現彩色愛心特效。通過實戰我們將學會createElement方法、appendChild方法、setTimeout方法。 案例演示 頁面出現後,滑鼠在 ...
  • HTML 介紹 引用 最全面的前端筆記來啦,包含了入門到入行的筆記,還支持實時效果預覽。小伙伴們不需要在花時間去寫筆記,或者是去網上找筆記了。面試高頻提問和你想要的筆記都幫你寫好了。支持移動端和PC端閱讀,深色和淺色模式。 原文鏈接:https://note.noxussj.top/ ::: war ...
  • 案例介紹 歡迎來到我的小院,我是霍大俠,恭喜你今天又要進步一點點了!我們來用JavaScript編程實戰案例,做一個大轉盤。當你難以抉擇的時候不妨用這個案例來幫你做選擇。通過編程實戰我們可以學到按鈕的點擊事件onclick()以及定時器的使用. 案例演示 每個選擇都展示在不同的盒子里,通過點擊中間的 ...
  • 原型鏈與繼承 new 關鍵字的執行過程 讓我們回顧一下,this 指向里提到的new關鍵字執行過程。 創建一個新的空對象 將構造函數的原型賦給新創建對象(實例)的隱式原型 利用顯式綁定將構造函數的 this 綁定到新創建對象併為其添加屬性 返回這個對象 手寫new關鍵字的執行過程: function ...
  • Visual Studio Code 介紹 Visual Studio Code 是一款非常輕量的前端代碼編寫工具,也是目前比較主流的。其中還包含了豐富的插件市場、非常好看的界面風格、可在軟體內直接使用命令行工具等。 :::warning 建議 在學習前端之前可以先把軟體下載好,方便實踐操作。 :: ...
  • 我們是袋鼠雲數棧 UED 團隊,致力於打造優秀的一站式數據中台產品。我們始終保持工匠精神,探索前端道路,為社區積累並傳播經驗價值。 本文作者:霜序(LuckyFBB) 前言 在之前的文章中,我們講述了 React 的數據流管理,從 props → context → Redux,以及 Redux 相 ...
  • //模擬對象 let obj = { numberParams:1, functionParams:() => { console.log('昨天基金全是綠的,只有我的眼睛是紅的'); }, objParams:{ a:1, b:2 } } const newObj = copyObj(obj); ...
  • 一、vuex介紹 目標 什麼是Vuex 為什麼學習Vuex 通信方案 | 組件關係 | 數據通信 | | | | | 父子關係 | 父傳子:props ; 子傳父:$emit | | 非父子關係 | vuex (一種組件通信方案) | Vuex是什麼 概念:專門在 Vue 中實現集中式狀態(數據)管 ...
一周排行
    -Advertisement-
    Play Games
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...