主頁 > 軟體設計 > 兩萬字長文-設計模式總結

兩萬字長文-設計模式總結

2021-07-31 08:53:05 軟體設計

設計模式總結

篇幅較長,建議收藏閱讀;
底部有公眾號、原始碼等,可先根據目錄到最下面掃碼關注或 star 原始碼;

戰術總結

??從開始學設計模式到現在,算是學了兩遍,但是這玩意怎么說呢,不是說學了就能會的那種,是需要經過一段時間的沉淀和積累的,有條件的話最好能直接上生產,但是需要注意專案的風險性接受程度
?? 一般來說,從專案的迭代之初,這個時間點是最考驗我們的設計、架構思維的,如果在這個階段你能有機會去參與到 代碼規范審查、代碼結構設計,那請收起你那不要錢的面子,這個時候就是你展現自己裝逼實力的時候,往上奧力給,其實這個階段如果你已經具備豐富的業務能力+你擁有較為豐富的架構思維,你可以自己嘗試通過各種設計組合去完成專案的初始化!但是這里有個問題,你要因為自己設計出問題而買單;
??如果你是個偶像實習生或者是個職場小鮮肉,那你是幸運的,你可以有個pm來幫你承擔部分風險,最起碼在review的時候能看出一點小問題,相當于給你寫的代碼免費提供了保險,小伙子,買保險不咯,那種可以讓你隨便寫代碼的保險哦!這個時候是可以讓自己在代碼設計方面有個很大的提升,多嘗試才能成功嗎,對吧,而且這部分業務可能也不是核心,所以大膽嘗試吧!

看看圖片

設計模式總覽

??這是張設計模式的關系圖,大家應該也能看出來,但是沒啥用吧?哈哈哈,可能吧,湊個數,這樣好看點,其實我們從圖中我們可以得出一個結論:設計模式是組合在一起使用的,那樣可以將整個業務都結合起來,對于有很強代碼閱讀能力的人來講,看完代碼,業務也就了解了(當然我是菜鳥,哈哈哈,之前看我pm的代碼,還是挺容易滲透到業務層面的)
??這張圖看看就得了,沒必要發大時間總是想著去關聯他們,到后面用的多了,自然而然就熟悉了,就會有一種從化神到飛升的感覺,一下子就悟了!

設計原則

??規約,是的可以這么理解,為了讓代碼統一,才有了這些原則,能夠讓代碼的質量更高,不管誰寫的代碼,大家都能讀懂,寫代碼隨心所欲并不是個好事,大家都要守規矩的,才不會浪費別人的時間,而設計原則就是起到這個作用的!

單一職責原則

字面上來看,就是每個物件都應該有自己的職責,別人不會影響自己,自己也不能插手去管別人;

比較官方的說法:

單一職責原則(Single Responsibility Principle,SRP)又稱單一功能原則,是面向物件的五個基本原則(SOLID)之一,它規定一個類應該只有一個發生變化的原因,該原則由羅伯特·C.馬丁(Robert C.Martin)在《敏捷軟體開發:原則、模式與實踐》一書中提出,

舉個栗子 :一個裝油的油壺,我們就不應該在賦予他裝飲用水的功能,那這樣每次我們用的時候還需要最前置的清洗,這樣功能混在一起,需要花費很多時間去維護,這樣得不償失!

開閉原則

在面向物件編程領域中,開閉原則 規定“軟體中的 物件__,模塊,函式等等)應該對于擴展是開放的,但是對于修改是封閉的 ”,這意味著一個物體是允許在不改變它的源代碼的前提下變更它的行為,該特性在產品化的環境中是特別有價值的,在這種環境中,改變源代碼需要代碼審查,單元測驗以及諸如此類的用以確保產品使用質量的程序,遵循這種原則的代碼在擴展時并不發生改變,因此無需上述的程序,參考自百度百科;

開閉原則(Open-Close Principle,OCP):就是對類的高度封裝,不要去破壞原有的代碼,我們可以基于他去進行擴展,或者通過方法去暴露他的屬性;

舉個很簡單的例子 :我們設計一個類,他具備了A功能給C這個類使用,突然B這個類覺得A功能不適合自己,然后偷偷的(很多業務不知道的情況下,我們不能隨便更改之前的功能)將A功能改成適合自己的A1功能,那這個時候C類就無法使用了,就要罵娘了!

里氏替換原則

嘖嘖,都是人,為啥差距這么大呢,都已人家名字進行命名:

里氏替換原則(Liskov Substitution Principle,LSP)是由麻省理工學院計算機科學系教授芭芭拉·利斯科夫(Barbara Liskov)于 1987 年在“面向物件技術的高峰會議”(OOPSLA)上發表的一篇文章《資料抽象和層次》(Data Abstractionand Hierarchy)里提出的,她提出:繼承必須確保超類所擁有的性質在子類中仍然成立,

這個原則大部分是限制在繼承之上的,大概可以分為幾種情況:

  • 子類可以實作父類的抽象方法,但是不能覆寫父類的方法

  • 子類可以有自己獨特的方法

  • 子類的入參需要更加寬松,比如父類接收引數ArrayList,那么子類應該要能接收ArrayList及其父類

  • 子類的回傳值,因該是父類可以接收的型別,父類回傳List,子類則需要回傳List的本身和實作者

這個原則,可以讓我們的代碼健壯性加強,而且擴展性也會有一定的提升,以及新需求介入的時候,代碼侵入性引起的風險也會降低

迪米特法則原則

1987年秋天,迪米特法則由美國Northeastern University的Ian Holland提出,被UML的創始者之一Booch等人普及,后來,因為經典著作The PragmaticProgrammer而廣為人知,迪米特法則(Law of Demeter,LoD)又稱為最少知道原則(Least KnowledgePrinciple,LKP),是指一個物件類對于其他物件類來說,知道得越少越好,也就是說,兩個類之間不要有過多的耦合關系,保持最少關聯性,

迪米特法則的暗語:不要和陌生人講話哦,跟自己朋友聊就行了!

舉個栗子 :部門的事業部經理想要知道整個部門的收入,他肯定是去找各個產品部的經理詢問資料然后拿出24K黃金的計算器開始求和,這里事業部經理肯定是不知道他們是怎么統計出來的,可能是底層打工人程式員從數倉里面拿出來的,也可能是dba從dts里面統計出來的,但是事業部總經理是不知道的,也不能知道,去自個寫代碼統計,然后各種資料不對!!其實也有但各司其事的意思;

介面隔離原則

《代碼整潔之道》的作者Robert C.Martin于2002年給“介面隔離原則”的定義是:客戶端不應該被迫依賴于它不使用的方法(Clients should not be forced todepend on methods they do not use),該原則還有另外一個定義:一個類對另一個類的依賴應該建立在最小的介面上(The dependency of one class toanother one should depend on the smallest possible interface),

介面隔離原則(Interface Segregation Principle,ISP)要求程式員盡量將臃腫龐大的介面拆分成更小的和更具體的介面,讓介面中只包含呼叫方需要用到的方法,

舉個栗子:我們設計一個介面,叫容器,我在其里面定義了,裝水、裝油、裝大米三個方法;然后我用我現在有個麻袋,去實作這個容器,這就有問題了,我只需要有裝大米的功能,現在我還要去實作裝水、裝油,我根本實作不了,這個時候在代碼里面只能不做任何處理,這樣導致無用代碼大量增加;而如果容器只提供裝東西的功能,我在寫一個介面:大米容器,里面只有裝大米的功能,這個時候只需要實作一個方法就行,雖然這樣類會多了不少,但是對于后續擴展就會減少很多無用代碼段;

依賴倒置原則

依賴倒置原則(Dependence Inversion Principle,DIP)是指在設計代碼架構時,高層模塊不應該依賴于低層模塊,二者都應該依賴于抽象,抽象不應該依賴于細節,細節應該依賴于抽象,在Spring生態中,我們在實際的c層或者其他的si(ServiceImpl)層級ddd下的manager層我們都應該只注入介面,而不是去注入ServiceImpl ,

簡單來講:最好不要兩個實作類互相呼叫,而是使用其介面進行呼叫

舉個栗子 :比如A介面有A1、A2兩個方法,然后B類和C類分別實作一個方法,B-A1,C-A2,然后有個D類現在要用A中的方法,他可以選擇分別引入 B類和C類,然后去呼叫,這樣就多了很多無效的代碼,引入A就可以了,就像我們平時的MVC模式下,我們一般在controller一般都是引入Service層的介面,不會去引入實作類!

合成復用原則

合成復用原則就是指在一個新的物件里通過關聯關系(包括組合關系和聚合關系)來使用一些已有的物件,使之成為新物件的一部分;新物件通過委派呼叫已有物件的方法達到復用其已有功能的目的,簡言之:要盡量使用組合/聚合關系,少用繼承,

這個原則用的很少,繼承的擴展性很強,所以里氏替換我是覺得有點沖突,不多講,聚合關系是很好用的一種思想,這個可以參考借鑒的,這個原則我有點沒吃透,大家可以補充!


創建型模式

使用花里胡哨的方式創建物件,其實就是將創建物件的程序給隱藏起來了,然后根據某些規則獲取這些物件,使其可以更加方便的使用,無需去new,這樣更靈活!

工廠模式(Factory Pattern)

工廠模式也稱簡單工廠模式,是創建型設計模式的一種,這種設計模式提供了按需創建物件的最佳方式,同時,這種創建方式不會對外暴露創建細節,并且會通過一個統一的介面創建所需物件;

其主要作用就是減少if else,然后對物件的創建進行統一的管理;

但是他也會存在一個問題,如果需要創建的型別過多,也會導致工廠類里面的if else大量增加,去維護對應的type也是需要花費一定時間的,而且功能類的數量也會大量增加;

舉個例子 :創建一個介面,容器(Column: 抽象產品類),然后有存液體的功能;然后有兩個實作類(WaterColumn:具體產品類)、(TeaColumn:具體產品類),再通過工廠類(ColumnFactory:工廠類,這里)去根據不同型別,選擇行創建不同功能類,想喝茶就去創建 Tea;大概就是如此!

喝茶

看看圖:

在這里插入圖片描述

抽象工廠模式(Abstract Factory Pattern)

抽象工廠模式(Abstract Factory Pattern)是圍繞一個超級工廠創建其他工廠,該超級工廠又稱為其他工廠的工廠,這種型別的設計模式屬于創建型模式,它提供了一種創建物件的最佳方式,

在抽象工廠模式中,介面是負責創建一個相關物件的工廠,不需要顯式指定它們的類,每個生成的工廠都能按照工廠模式提供物件,

這里可以理解為,一個很大的工廠,比如電腦廠(ComputerFactory),他可能旗下還有 螢屏廠(MonitorFactory)、硬碟廠(HardDiskFactory)等,這里電腦廠就是抽象工廠,然后子廠再去生產指定的東西(功能類);

其實這種模式在平時開發用的不算多,大多數情況下通過簡單工廠就能完成,而且這種模式下,會導致子類工廠需要去實作自己沒有的功能,這樣不算符合介面隔離原則,但是我們可以稍作修改,看下圖,我們可以在新增一個中間實作(CommonFactory),他不做任何處理,就替代功能類去實作自己沒能力完成的功能,他自己的作用就是減少冗余的無用的代碼;

看看圖:

抽象工廠

單例模式(Singleton Pattern)

單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一,這種型別的設計模式屬于創建型模式,它提供了一種創建物件的最佳方式之一(主要減少記憶體占用),

這種模式涉及到一個單一的類,該類負責創建自己的物件,同時確保只有單個物件被創建,這個類提供了一種訪問其唯一的物件的方式,可以直接訪問,不需要實體化該類的物件,

可以總結出一條經驗,單例模式主要解決的是一個全域使用的類,被頻繁地創建與銷毀,從而提升代碼的整體性能;

這個模式沒什么好說的,是比較簡單的,主要目的就是為了減少物件頻繁創建而浪費記憶體

建造者模式(Builder Pattern)

建造者模式(Builder Pattern)使用多個簡單的物件一步一步構建成一個復雜的物件,這種型別的設計模式屬于創建型模式,它提供了一種創建物件的最佳方式之一,Builder 類會一步一步構造最終的物件,該 Builder 類是獨立于其他物件的,相當于聚合其他的類,完成最終可供選擇的產品;這里可以抽象為表示與構建程序進行分離,客戶端只需關注表示出來的東西;

建造者模式的經典案例就是lombok的@Builder注解,提供建造者模式去構建自己最后想要的物件,這里沒有用的小伙伴可以去試試;

這里舉個栗子 :有個電腦店(ComputerBuilder),他有很多材料可以使用,最后需要給出幾套方案:有高配的、中配的、低配的;顧客想買的話就直接提走就行了,不需要自己組裝電腦(當然向我們程式員肯定是要自己體驗組裝的樂趣了😁),這大概就是建造者模式的概念;

建造者模式

原型模式(Prototype Pattern)

原型模式(Prototype Pattern)是用于創建重復的物件,同時又能保證性能,這種模式是實作了一個原型介面,該介面用于創建當前物件的克隆,當直接創建物件的代價比較大時(存在一個物件創建程序很復雜的情況,這樣就需要選擇去復用物件了),則采用這種模式,例如,一個物件需要在一個高代價的資料庫操作之后被創建(一般都是初始化的資料,另外一種方式則是放到redis這一類快取資料庫中),我們可以快取該物件,在下一個請求時回傳它的克隆,在需要的時候更新資料庫,以此來減少資料庫呼叫,

原型可以涉及到java中的深拷貝的創建方式,使用的就是.clone方法,這個模式其實在代碼中用的很多,比如將重復使用的物件放到map中,或者放在ThreadLocal中都是這種模式的思想

原型模式


結構型模式

結構結構,指的就是物件有獨特的結構,就是通過物件的各種組合來達到產品需求;它主要包括配接器模式、橋接模式、組合模式、裝飾模式、外觀模式、享元模式、代理模式這個七個模式,

配接器(Adapter Pattern)

配接器模式(Adapter Pattern)是作為兩個不兼容的介面之間的橋梁,這種型別的設計模式屬于結構型模式,它結合了兩個獨立介面的功能,這種模式涉及到一個單一的類,該類負責加入獨立的或不兼容的介面功能,

配接器模式的主要作用是把原本不兼容的介面通過適配修改做到統一,方便呼叫方使用.

生活中有很多這種案例,最常見的就是電源配接器,有電腦的、手機的都是將家庭用電轉換成電子產品對應的充電需要的電壓數;

這里舉個小栗子 :有一個遠古的MP3播放器,正在努力的播放MP3檔案,突然新生想法,我要播放MP4檔案,甚至avi檔案;然后開始動手做了個配接器(MediaAdapter),然后給他賦予了播放前面兩種檔案的能力,然后在把配接器插入到之前老的MP3播放器中,然后就可以美滋滋的看著avi檔案的電影了;

美滋滋

看看圖:
在這里插入圖片描述

橋接模式(Bridge Pattern)

橋接(Bridge Pattern)是用于把抽象化與實作化解耦,使得二者可以獨立變化,然后兩者通過一個抽象類來進行橋接;這種模式涉及到一個作為橋接的介面,使得物體類的功能獨立于介面實作類,這兩種型別的類可被結構化改變而互不影響,可以理解為 A功能類、B功能類,然后一個抽象類C作為橋接者,將A和B兩者連接起來,這樣A、B兩者可以修改自己的類的行為,然后C不去橋接兩者,這樣可以靈活的配置;如果出現很多組合,然而每一個類都實作不同的服務,可能會出現笛卡兒積,這個時候用橋接就特別爽了!

看看這個例子: 我是個吃貨😂,假設有家店,他有很多菜品(Cuisine),這些菜品呢,就是那個橋接者,然后呢,有面食(Pasta)、米粉(RiceFlour);然后廚師會兩種做法水煮(Boiled)、爆炒(StirFry);那么笛卡爾積就來,2 * 2 = 4,就存在四個菜品:水煮面、爆炒面、水煮粉、爆炒粉;突然廚子A離職了,然后廚子B來了,假設他是個菜鳥,只會水煮,那么菜品只能減少了(Cuisine);但是只要廚子A又回來了,或者將爆炒改良了成魔鬼辣椒爆炒,但是對于菜品來說,只需要將面食丟給廚子就行了,我菜品上又可以加兩道菜;這就是橋接的好處就是應對這種會存在組合關系,會出現笛卡爾積的場景;

橋接模式

組合模式(Composite Pattern)

組合模式(Composite Pattern):有時候又叫做部分-整體模式,它使我們樹型結構的問題中,模糊了簡單元素和復雜元素的概念,客戶程式可以像處理簡單元素一樣來處理復雜元素,從而使得客戶程式與復雜元素的內部結構解耦,

組合模式讓你可以優化處理遞回或分級資料結構,有許多關于分級資料結構的例子,使得組合模式非常有用武之地,關于分級資料結構的一個普遍性的例子是你每次使用電腦時所遇到的:檔案系統,檔案系統由目錄和檔案組成,每個目錄都可以裝內容,目錄的內容可以是檔案,也可以是目錄,按照這種方式,計算機的檔案系統就是以遞回結構來組織的,如果你想要描述這樣的資料結構,那么你可以使用組合模式Composite, — from 百度百科

組合模式,光看概念可能會很模糊,那就舉個栗子:什么天氣穿什么衣服;首先我們有很多衣服 長袖、短袖、五分褲、九分褲(這里可以通過橋接、建造者去組合);然后有幾個條件:溫度有大于、小于30°,太陽分 有、無,這里可能還有風量大小之類的,就先不說了;然后會出現很多組合:

  • 溫度>30°,有太陽 ==》 穿短袖、五分褲

  • 溫度>30°,無太陽 ==》 穿短袖、九分褲

  • 溫度<30°,有太陽 ==》 穿長袖、五分褲

  • 溫度<30°,無太陽 ==》 穿長袖、九分褲

看上面我們可以這么做,將每個條件抽離出來(溫度、太陽)作為一個個節點,然后再將 >、<、=、有、無這一類作為對比規則保存起來,用一個switch+列舉保存;然后開始組合 溫度節點 → 規則與界限(>, 30°)→ 太陽節點 → 規則與界限(=, 有太陽)→ 果實節點(這里就是具體回傳 == 穿短袖、五分褲);這樣就可以組合出很多場景來了,這樣雖然看起來沒有if else來的快,可是之后需要加 溫度界限為 10°、 20°等情況的時候,有需要加很多if else,這樣維護起來就相當麻煩,而組合模式,這需要加上一個條件節點、一個規則節點和果實節點,也不會對之前的代碼有很大的侵入性;

當然這是舉個栗子,組合模式也可以用來做決策樹、根據用戶性別和年齡推薦不同類目的產品;

看看圖:

組合模式

裝飾器模式(Decorator Pattern)

裝飾器模式(Decorator Pattern)允許向一個現有的物件添加新的功能,同時又不改變其結構,這種型別的設計模式屬于結構型模式,它是作為現有的類的一個包裝,這種模式類似于俄羅斯套娃;

這種模式并不少見,很多熟悉的場景都用到了裝飾器模式,例如是否熟悉 new BufferedReader(newFileReader(""));這段代碼?大家在學習Java開發的位元組流、字符流和檔案流的內容時都見到過,一層嵌套一層,位元組流轉字符流等,這就是使用裝飾器模式的一種體現;

再來舉個栗子 ,讓大家更明白:假設我有輛裝逼的機車(Locomotive),雖然很裝逼,但是總感覺有點不足,那個轟鳴聲雖然大;但是不夠,于是我想改造,裝個音箱來放dj(裝飾物:音箱),這個時候我還需要一個放音箱的架子(CarDecorator);然后我把音箱放上去就可以快樂的聽dj了,快樂的裝逼了!!

裝逼

看圖:

裝飾器模式

外觀模式(Facade Pattern)

外觀模式(Facade Pattern)隱藏系統的復雜性,并向客戶端提供了一個客戶端可以訪問系統的介面,這種型別的設計模式屬于結構型模式,它向現有的系統添加一個介面,來隱藏系統的復雜性,他類似于在多個系統中做一個中間者的模式,封裝一個復雜的邏輯給呼叫方使用;

舉個小例子:相當于有兩個系統A、B;這兩個系統都需要使用支付,但是支付系統C想呼叫很復雜,于是乎又來了第三個系統D(支付sdk);此時A、B只需要引入C系統的sdk即可選擇支付方式;之后想增加支付方式,繼續往系統D中添加即可;

看圖:

外觀模式

享元模式(Flyweight Pattern)

享元模式(Flyweight Pattern)主要用于減少創建物件的數量,以減少記憶體占用和提高性能;較大的物件通常比較耗費記憶體,需要查詢大量的介面或使用資料庫資源,因此有必要統一抽離出來作為共享物件使用,像資料庫連接池就是很好的一種實作;

這個模式就是將大物件復用,把其放到快取中;這里是完全參考菜鳥上面的享元模式,就是將圓的顏色進行快取,然后其他屬性隨機變化;

直接看圖:

享元模式

代理模式(Proxy Pattern)

在代理模式(Proxy Pattern)中,一個類代表另一個類的功能,這種型別的設計模式屬于結構型模式,在代理模式中,我們創建具有現有物件的物件,以便向外界提供功能介面,

代理模式并不少見,想在java中就有jdk動態代理,spring的cglib等都是使用了代理模式;

這里舉個栗子:有一張照片(Image ),需要從磁盤里面取出來,如果我們每次都去磁盤里面區,就會造成大量的IO(之前的設計是如此,不好更改),會影響系統的性能,而這個時候就可以創建一個代理類,去代替這個物件對外提供訪問入口,但是不會改變其功能,依舊可以展示圖片,只是不需要去磁盤中取;

看圖:

代理模式

行為型模式

每個物件都在盡自己的職責在做事,可以理解為這一類設計模式是通過自己的行為去達成目標,而不需外部繼續實作

責任鏈(Chain of Responsibility Pattern)

責任鏈模式(Chain of Responsibility Pattern)為請求創建了一個接收者物件的鏈,這種模式給予請求的型別,對請求的發送者和接收者進行解耦,這種型別的設計模式屬于行為型模式,一般來說,這種模式下,上一個處理不了或者已經處理了一次,便會把自己的物件參考丟給下一個處理節點繼續操作,他們都繼承了同一個抽象,而該抽象中包含了下一個節點的參考;相當于是一個攔截鏈,處理不了就回去請求下一個處理者的幫助,也有可能是每個攔截節點都會對一個物件添加一個新的功能點;

這里舉個例子: 有三種日志級別,ConsoleLogger、DebugLogger、ErrorLogger,假設我們初始化的時候,使其對應的級別為1,2,3;那么這個時候我們針對不同級別的日志輸出不同的內容,假設我們這里的優先級是,3可以列印 123, 2可以列印 12,1只能列印1;當我們是3的時候,此時我們的規則就是 3≥1列印 console級別,3≥2列印debug級別,3≥3列印error級別;如果不用責任鏈,我們可能就緒要寫很多種if else的組合;使用責任鏈后:(AbstractLogger),然后幾個級別繼承該抽象,然后里面存有 next節點,處理完該節點夠,繼續處理next的節點;

看圖吧:

責任鏈模式

命令模式(Command Pattern)

命令模式(Command Pattern)是一種資料驅動的設計模式,它屬于行為型模式,請求以命令的形式包裹在物件中,并傳給呼叫物件,呼叫物件尋找可以處理該命令的合適的物件,并把該命令傳給相應的物件,該物件執行命令,命令模式是把邏輯實作與操作請求分離,降低耦合,方便擴展,命令模式是行為模式中的一種,以資料驅動的方式將命令物件用建構式的方式傳遞給呼叫者,呼叫者再提供相應的實作,為命令執行提供操作方法

這種模式用的比較少,但是有挺常見,比如我們最愛用的 CV大法;

來一個例子: 模擬一個點菜系統,當顧客下單點菜的時候,他肯定是找服務員(XiaoEr)去下單,然后服務員再去找廚師做菜,在這里可以理解,顧客的 江西廚師做的江西菜就是一個命令,然后告訴小二,然后小二會將這條命令傳遞到廚師就行了,顧客無需跟廚師進行直接交流;反過來想,如果廚師已經做好了菜品,小二只需要根據 顧客的命令 拿到對應的菜品即可;

看圖:

命令列模式

解釋器模式(Interpreter Pattern)

解釋器模式(Interpreter Pattern)提供了評估語言的語法或運算式的方式,它屬于行為型模式,這種模式實作了一個運算式介面,該介面解釋一個特定的背景關系,這種模式被用在 SQL 決議、符號處理引擎等,

這個模式平時用的不多;主要是用來設定多個運算式模板,達到代碼復用的目的,比如我要校驗一個sql陳述句是否是select,然后在做出相應的處理;不多說

看圖:

解釋器模式

迭代器模式(Iterator Pattern)

迭代器模式(Iterator Pattern)是 Java編程環境中非常常用的設計模式,這種模式用于順序訪問集合物件的元素,不需要知道集合物件的底層表示,迭代器模式屬于行為型模式,可以理解為是for的高級封裝,是同一個功能的不同實作;迭代器模式的優點是能夠以相同的方式遍歷不同的資料結構元素,這些資料結構包括:陣列、鏈表和樹等,而用戶在使用遍歷時,并不需要關心每一種資料結構的遍歷處理邏輯,做到讓使用變得統一易用

迭代器模式其實沒什么可講的,在java中就很常見,有很多實作,這幾就簡單參考菜鳥上面的案例,遍歷名字列印在控制臺;這個也沒必要說很多;

看圖:

迭代器模式

中介者模式(Mediator Pattern)

中介者模式(Mediator Pattern)是用來降低多個物件和類之間的通信復雜性,這種模式提供了一個中介類,該類通常處理不同類之間的通信,并支持松耦合,使代碼易于維護,中介者模式屬于行為型模式,其實也可以理解為將復雜的類呼叫關系,全部堆到中介者的身上,以此類維護這些類的關系;

又要舉個例子來講講:中介者模式當然要扯上租房中介了,假設沒有中介的情況下,A房東有房子,B租客直接聯系了A,然后A去接B,到了房子,看房子,然后租下,然后B的朋友C租客也想租房子,B聯系房東,房東到B那取得C的聯系方式,加了微信,問了C位置,又去接他來看房,然后房東累死了,C不租了;房東一怒以下,花點錢請中介,然你們租客租房多花點錢;于是乎中介來了;現在有個D租房,直接找中介,中介接他來看房,房東不管了,中介負責告訴房東結果,最后付錢簽合同在找房東即可;這里中介者就省去了人找人(類與類的耦合),又要房東去接,又要介紹房子等繁瑣的事情;吐槽:房租好貴啊!😭

看圖:

中介者模式

備忘錄模式(Memento Pattern)

備忘錄模式(Memento Pattern)保存一個物件的某個狀態的快照(會存在多個快照),以便在適當的時候恢復物件,備忘錄模式屬于行為型模式,在功能實作上,是以不破壞原物件為基礎增加備忘錄操作類,記錄原物件的行為,從而實作備忘錄模式;相當于記錄了多個版本,隨時有恢復的手段;類似于k8s的彈性伸縮,或者說虛擬機的快照版本;提供后悔的功能;

備忘錄模式,其實就是將歷史版本存放起來,便于之后去取出來進行回滾,其實資料庫里面取最后一次操作日志是同一個道理,想拉鏈表也是如此設計,記錄很多版本;

舉個例子 :我現在有個操作,每個操作都對應一個版本;現在我希望我有個功能可以去實作我能回到上一個版本或者任意版本;有個操作(Originator)還有版本號,這個每次操作都會記錄到備忘錄;然后就有一個備忘錄記錄操作內容和版本號(Memento),并將歷史版本存起來,這里是放到List中;之后想回滾直接取出來就行了;

看圖:

備忘錄模式

觀察者模式(Observer Pattern)

觀察者模式(Observer Pattern)一般用于一對多的情況下,比如,當一個物件被修改時,則會自動通知依賴它的物件,觀察者模式屬于行為型模式,簡單來講,觀察者模式是指當一個行為發生時,一個用戶傳遞資訊,另一個用戶接收資訊并做出相應的處理,行為和接收者之間沒有直接的耦合關聯,這個也可以參考發布訂閱模式,在Mq中是非常常見的一種模式;

把觀察者模式說成發布訂閱模式也很類似,意味著所有訂閱發布者訊息的,當訊息改變,或者有新的傳遞的時候,訂閱者(觀察者)是能實時接收到的,而自己無需做任何操作;

來個小例子: 在有訂單的系統中,都會有存在發訊息提示管理員有人下單了,有釘釘、微信模板、短信等推送方式;這里我們模擬下單操作,首先會有個事件處理器(EventHandler)里面只有處理訊息的功能,這里一般會把訂單資訊傳遞過去;然后有兩個實作(MQEventHandler,MessageEventHandler)里面是MQ去存庫和發短信的操作;然后就是有個監聽管理器(ListenerManager),這里會初始化所有需要通知的處理器(訂閱者);然后就是發布者(OrderService)這個設計為抽象類,這里在訂單下單成功,然后更具業務需求選擇指定的發送給哪個訂閱者,當然我們也可以設計成默認發所有;

看圖吧:

觀察者模式

狀態模式(State Pattern)

在狀態模式(State Pattern)中,背景關系類的行為是基于它的狀態改變的,這種型別的設計模式屬于行為型模式,在狀態模式中,我們創建表示各種狀態的物件和一個行為隨著狀態物件改變而改變的 context 物件(將狀態類賦值給背景關系),其實這個很常見,比如登錄和不登錄場景下,就是不同的狀態對應不同的頁面;每種狀態只關心自己的行為,而狀態和行為的表示,則交由context背景關系去表示,這樣看上去是 state這個物件一直在改變;

這里有個小場景:假設我們下單現在之后兩個操作,開始下單準備(StartState)、下單完成狀態(StopState)、背景關系(Context)用來管理表示這些狀態;當進行每一個操作的時候,將其賦值給背景關系,用他來對外暴露;這個時候的背景關系是需要根據 兩種狀態來進行改變的;

看圖:

狀態模式

策略模式(Strategy Pattern)

在策略模式(Strategy Pattern)中,一個類的行為或其演算法可以在運行時更改且不影響呼叫者的代碼邏輯,這種型別的設計模式屬于行為型模式,在策略模式中,我們創建表示各種策略的物件(不同行為或不同演算法、規則模板等)和一個行為隨著策略物件改變而改變的 context 物件,策略物件改變 context 物件的執行演算法,

這里舉個敲簡單的例子: 我有兩套演算法,很高大上的演算法😎,加法(AddStrategy)、乘法(MutilStrategy),這些都繼承策略模板(Strategy),該策略就是計算;然后就是有個跟演算法實作無關的類,也即是背景關系(Context),只需要傳遞指定的演算法就行,然后不需要修改任何代碼,當修改演算法時,背景關系對應的反饋也會隨之修改;

看圖吧:

策略模式

模板模式(Template Pattern)

在模板模式(Template Pattern)中,一個抽象類公開定義了執行它的方法的方式/模板(就是方法ABC,其子類都有這些流程),它的子類可以按需要重寫方法實作,如果有需要實作的,可以使用公共的繼承類去減少冗余的實作代碼,但呼叫將以抽象類中定義的方式進行,這種型別的設計模式屬于行為型模式,模板模式的核心設計思路是通過在抽象類中定義抽象方法的執行順序,并將抽象方法設定為只有子類實作,但不設計獨立訪問的方法,

這種模式還是挺多地方,或者場景都用到了,比如工廠里面的活,生產一瓶牛奶,取出盒子 → 裝入牛奶 → 塑封 → 粘上習慣 → 打包裝箱;這些都可以抽象成模板,但是裝入什么牛奶,用什么習慣就有不同牛奶品牌去決定;

舉個在簡單點的例子: 吃貨的我,來說的跟做菜相關的,我們做菜可以分為 清理菜(cleaning) → 做菜(doCooking) → 裝盤(finish),將這些步驟全部封裝起來做一個模板,然后具體子類去實作就行,我們這里還可以提取出公共實作,然后子類實作自己的步驟即可,比如白菜(Dabaicai),比較普通,需要全部做完上述模板操作,而我有個精品的五花肉(WuHuaRou),我直接做就可以了,不需要處理,兩步就搞定了;這樣防止過多冗余代碼,我們就可以搞個公共類去空實作;

看圖:

模板模式

訪問者模式(Visitor Pattern)

在訪問者模式(Visitor Pattern)中,我們使用了一個訪問者類去得到自己想要的結果,簡單來說就是訪問者想通過指定的演算法得到自己想要的結果,這個指定的演算法是由被訪問者提供的,

舉個例子吧: 存在兩個訪問者校長(Principal)、家長(Parent);兩個被訪問者老師(Teacher),用于給校長匯報及格率,學生(Student)用于給自己家長匯報班級排名;當校長或者家長突然不想看及格率胡總和排名了,對應的老師、學生就需要對自己原有的邏輯或者演算法進行修改;這就是被訪問者做出的行為;

看圖:

訪問者模式

全文矯情總結

其實就是簡單的寫了個目錄一樣,算是一篇快速過一遍概念的總覽文章,具體的代碼還是需要到具體的文章上去看看,或者自己根據代碼去自己手動敲一下(強烈推薦),最好是敲一遍我寫的,然后理解之后再去自己像一個場景,然后去實作它,這樣之后實際生產中就會得心應手!!加油吧!!

重點 之后詳細文章可能會放在公眾號,或者在csdn中繼續發;請持續關注:

公眾號 掃碼關注,愛搞技術的吳同學 ,公眾號上會經常寫實用性的文章,謝謝關注!!回復:“加好友”,可獲取我的微信二維碼,歡迎加好友,一起學習!!!
微信公眾號
大量原始碼 歡迎star,可能會分享微服務實戰,分頁插件等;gitee-yysimple

感謝大家閱讀!!!

參考:https://www.runoob.com/design-pattern/design-pattern-tutorial.html

參考:https://weread.qq.com/web/reader/bcf32900724708cbbcf08c1k8f132430178f14e45fce0f7(小傅哥)

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/291087.html

標籤:其他

上一篇:演算法效率(時間與空間復雜度)

下一篇:聊聊百度搜索背后的故事

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more