GoF:
必背
24種設計模式 :
- 設計原則: 設計模式(總綱)
- 創建型(6): 單例模式 簡單工廠模式 工廠方法模式 抽象工廠模式 建造者模式 原型模式
- 結構型(7 ,2個器,5個兩字的): 代理模式 配接器模式 裝飾器模式 橋接模式 組合模式 享元模式 外觀模式
- 行為型(11): 觀察者模式 模板方法模式 命令模式 狀態模式 職責鏈模式 解釋器模式 中介者模式
- 訪問者模式 策略模式 備忘錄模式 迭代器模式
3個者 ,3個兩字的,2個器,2個三字的,1個四字的
六大規則 :
- 單一職責原則 (Single Responsiblity Principle SRP)
- 開閉原則(Open Closed Principle,OCP)
- 里氏代換原則(Liskov Substitution Principle,LSP)
- 依賴倒置原則(Dependency Inversion Principle,DIP)
- 介面隔離原則(Interface Segregation Principle,ISP)
- 最小知識原則(Principle of Least Knowledge,PLK,也叫迪米特法則)
其他介紹
- 單一職責原則:描述的意思是每個類都只負責單一的功能,切不可太多,并且一個類應當盡量的把一個功能做到極致,
- 里氏替換原則:這個原則表達的意思是一個子類應該可以替換掉父類并且可以正常作業,(由于有了里氏替換原則,才使得開發-關閉有了可能,因為子類的可替換性使得使用父型別別的模塊在無需修改的情況下就可以擴展)
- 介面隔離原則:也稱介面最小化原則,強調的是一個介面擁有的行為應該盡可能的小,
- 依賴倒置原則:這個原則描述的是高層模塊不該依賴于低層模塊(高層要通過抽象或者介面依賴底層的意思,如Controller是高層,Dao是低層),二者都應該依賴于抽象,抽象不應該依賴于細節,細節應該依賴于抽象, 即針對介面編程,不要針對實作編程,(介面的好處是只要把對外介面定義好,那么內部實作無論多復雜,怎么改動都和外部呼叫者無關)
- 迪米特原則:也稱最小知道原則,即一個類應該盡量不要知道其他類太多的東西,不要和陌生的類有太多接觸,
- 開-閉原則:最后一個原則,一句話,對修改關閉,對擴展開放,
其他隨筆:
如果想成為一名更優秀的軟體設計師,了解軟體設計的演變程序比學習優秀設計本身更有價值,因為設計的演變程序中蘊含著大智慧,
理解:是不是說其實目前我們所用到的優秀中間件,框架,MQ,Zookeeper,redis等想學習了深入理解他們首選就要先知道為什么我們選擇他,他解決了哪些痛點,難點?又是如何一步一步演化為先如今的功能樣式的,在設計模式中,除了了解這個設計模式是什么?還要了解為什么這樣設計才是好的?如何想到這樣的設計的?
WHAT WHY HOW
P16 :UML圖的認識
面向物件的編程,并不是類越多越好,類的劃分是為了封裝,但分類的基礎是抽象,具有相同屬性和功能的物件的抽象集合才是類,
所以因為一點變化就創建一個類是不行的,得是一種物件的描述才行,如動物下分雞鴨魚,而不是一件商品打678折或者滿500減100這種情況劃分類,
演算法或者細節等如打折的改變一般喜歡用策略模式來封裝,策略模式就是用來封裝演算法的,在實踐中,我們可以用它來封裝幾乎任何型別的規則,只要在分析程序中聽到需要在不同時間應用不同的業務規則,就可以考慮使用策略模式處理這種變化的可能性,
盡量的讓客戶端或者呼叫者認識(或者說參考,創建都可以)最少的類或者說知識,其他呼叫端不必認識或者知道的全部封裝起來,遵守最小知道原則,
高手和菜鳥的區別就是高手可以花同樣的代價獲取最大的利益或者說做同樣的事花最小的代價,
單一職責原則:就一個類而言,應該僅有一個引起它變化的原因,(因為他職責單一,所以只有份屬于他的職責功能變化了才去改變他,其他情況下他是不變的,)
模板方法模式
模板方法模式:定義一個操作中的演算法的骨架(流程),而將一些步驟延遲到子類中,模板方法使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟,
大體是抽象類定義演算法的股價,具體子類重定義相關細節的方法來實作具體的步驟,模板方法模式是通過把不變行為搬移到超類,去除子類中的重復代碼來體現他的優勢,是一個 很好的代碼服用平臺,可以幫子類擺脫重復的不變行為的糾纏,
例子:每個考生的考試試卷及答案可以提煉為模板方法模式,即除了答案作為抽象方法給每個考生重寫實作,其他不變的框架都在父類上定義,
大眾汽車的生產,流程都是一樣的,但是具體的細節如用的材料,車型,定位的不同而生產出不一樣的大眾汽車,高爾夫,途觀,帕薩特,
汽車玻璃的生產,不同的汽車有不同的擋風玻璃形狀,但生產擋風玻璃的流程和模型是一樣的,只是根據不同的汽車玻璃形狀來生產,
模板方法中,所以不變的都提升到父類中,再讓具體的變化用子類去重寫實作,
當我們要完成在某一細節層次一致的一個程序或一系列步驟,但其個別不走在更詳細的層次上的實作可能不同時,通常選擇用模板方法模式來處理,
迪米特法則
也叫最小知道原則
沒有管理,單靠人際關系協調是很難辦成事兒的,因為三個和尚沒水喝,互相推諉,
定義:如果兩個類不必彼此直接通信,那么這兩個類就不應當發生直接的相互作用,如果其中一個類需要呼叫另外一個類的某個方法的話,可以通過第三者轉發這個呼叫,???第三者?(意思是我想要丈母娘做晚飯我不需要直接叫她,我可以通過寶寶來轉發呼叫)
強調了類之間的松耦合,耦合越弱,越有利于復用,這樣當一個弱耦合的類被修改,不會對有關系的類造成波及,
外觀模式
體現依賴倒置和迪米特原則
定義:為子系統中的一組介面提供一個一致的界面,此模式定義了一個高層介面,這個介面使得這一子系統更加容易使用,
即讓呼叫者呼叫一個統一的入口介面,這個介面整合了需要被呼叫類的功能,通過參考整合,向外提供方法服務,
例子:三層架構Controller》Service》Dao ,層與層之間建立外觀Facade,即都向上提供服務;浙江ocrm老系統屬于遺留大型系統,與其互動運用外觀模式,通過設計一個Facade類,來提供清晰簡單的介面,讓訂單中心與Facade物件互動,Facade物件與ocrm老系統互動復雜的作業;不是直接買股票而是通過基金來買股票,基金就是外觀物件;功能按鈕,一個功能里面有多個功能組成,
俄羅斯方塊游戲的邏輯本質:
游戲區域可以設計為一個二維整形資料來表示坐標,如寬10,高20.例子:
int [][] arraySquare = new int[10][20];
那么整個方塊的移動其實就是陣列的下標變化,而每個陣列的值就是是否存在方塊的標志,存在為1,不存在預設為0.
單一職責原則:
職責分離是因為如果一個類承擔的職責過多,就等于把這些類耦合在一起,需要分離開,如找出哪些是界面,哪些是游戲邏輯,進行分離,
開閉原則:
典型例子:一國兩制.
上班時間打卡制度:對作業時間或業績成效的修改關閉,對時間制度拓展的開發,如彈性作業、打卡時間波動8:30-9:30
軟體物體(類、模塊、函式等)應該可以擴展,但不能修改,但這只是理想上的原則,要盡量做到,則必須在設計時先猜測出最有可能發生的變化種類,然后構造抽象來隔離這些變化,
面對需求,對程式的改動是增加新代碼進行的,而不是更改現有的代碼,而這也就需要通過構造抽象來隔離,
如計算器構造運算類,加減乘除繼承該運算類;匯出excel檔案的匯出基類,具體的匯出檔案繼承基類來豐富匯出欄位等,
面向物件的4大好處:可維護,可擴展,可復用,靈活性好,
PC電腦硬體的發展,和面向物件思想的發展是類似的,(遵循6大準則)
程式中所有的依賴關系都是終止于抽象類或者介面,那就是面向物件的設計,反之就是程序化的設計了,
時間萬物都是遵循某種類似的規律,誰先把握了這些規律,誰就最早成為了強者,
裝飾器模式
例子:人和衣服搭配;I/O流的裝飾器類;工廠的產品包裝,如糖果和外包裝,汽車和內飾配置,
建造者模式要求建造的程序必須是穩定的,與裝飾器模式的區別是裝飾器模式的建造程序是不穩定的,他可以有非常多種搭配,
裝飾模式:動態地給一個物件添加一些額外的職責,就增加功能來說,裝飾模式比生成子類更為靈活(裝飾模式也是要生成繼承于組件的子類,然后在該子類基礎上增加set該組件的功能,滿足后面繼承該裝飾器類的子類可以在不影響組件功能的情況下增加額外功能,)
裝飾模式的使用特點:
裝飾模式是為已有功能動態地添加更多功能的一種方式,避免在已有的主類上加入新的欄位,方法等增加了主類的復雜度,且新加的額外功能只適用于滿足一些特定情況下才會執行的特殊行為的需要,這時候如果用裝飾模式,把要裝飾的功能放在單獨的類中,讓這個類包裝他要裝飾的物件,則當需要執行特殊行為或者說額外功能時,就可以有選擇按順序地運行使用裝飾功能的包裝物件了,(優點:有效地把類的核心職責和裝飾功能區分開)
代理模式
中間商
例子:簽證代理,開公司代理
代理模式中真實物體和代理類共用介面,即實作同一個介面,這其中代理類會保存一個真實物體的參考,在呼叫方呼叫介面方法時,代理類就能通過多型代替物體,
使用場合:
遠程代理 :?
虛擬代理: html網頁上的圖片框通過虛擬代理代替了真實的圖片,存盤了真是圖片的路徑和尺寸,這樣等加載好了就能替換過來,在這之前通過虛擬代理保持了網頁的格式和輪廓,
安全代理:用來控制真實物件訪問時的權限,
智能指引:指呼叫真實的物件時,代理處理另外一些事,也就是除了代理的事還多做些其他事,
工廠方法模式
gg
例子:大規模生產時,如富士康不同款的手機生產對應不同的流水線,
工廠方法模式是在簡單工廠模式的基礎上的抽象和擴張,即在簡單工廠模式上,把工廠抽象出來,讓要生產的具體產品分別有對應生產該產品具體的工廠類(繼承于抽象工廠,通過多型來實作),其優點在于把簡單工廠的內部邏輯判斷(選擇生產什么產品)轉移到了客戶端代碼上來,現在想要增加新的產品,本來是修改工程類,現在是修改客戶端呼叫,增加新的工廠,克服了簡單工廠違背的開發-封閉原則的缺點,
(PS:但還是沒能避免修改客戶端的代碼,可以通過簡單工廠模式加反射來避免工廠類中的分支判斷問題替代工廠方法,)
原型模式
復制
例子:列印機;簡歷復制;傳單;電影膠卷
原型模式:用原型實體指定創建物件的種類,并通過拷貝這些原型創建新的物件,
提供一個clone方法來進行原型物件復制,
clone有深復制和淺復制區分,
一般在初始化資訊不發生變化的情況下,克隆是最后的辦法,這既隱藏了物件創建的細節,又大大提高了性能(為什么這么說?),
建造者模式
定義:將一個復雜物件的構建與它的表示分離,使得同樣的構建程序可以創建不同的表示,
建筑這模式的程序是穩定的,而具體建造的細節是不同的,使用建造者模式時,用戶只需指定需要建造的型別就可以得到它們,而具體建造的程序和細節就不需要知道了,
構建一個抽象的建造類,讓要實作的產品繼承這個建造類,實作里面的抽象方法(建造細節),
還要有個指揮者類(專案經理),用它來控制建造程序,也用它來隔離用戶與建造程序的關聯;即用戶把想要的產品建造類給我,具體怎么組裝用戶想要的產品交給指揮者,
例子:建造人;肯德基麥當勞的炸雞生產是建造者模式,而不是靠廚師;建造房子,
建造者模式是在當創建復雜物件的演算法(方法)應該獨立于該物件的組成部分以及他們的裝配方式時適用的模式,
那建造者模式和模板方法的區別?
A:模板方法模式是純粹給演算法用的,用于演算法架構與演算法細節分離;而建造者模式是給演算法和他的組成部分用的,用于演算法和物件結合時用?
觀察者模式
觀察者模式,又叫發布/訂閱模式
一對多關系用
一般是有個介面類主題或者叫抽象通知者(Subject),一個介面類觀察者(Observer),具體的主題如微博關注的明星實作介面類主題,粉絲實作觀察者,
依賴倒置原則的最佳體現,
例子:idea啟動后啟動按鈕的變化,log視窗的顯示等就是依賴于觀察者模式;訂閱報紙;微博關注的人更新微博,粉絲就能收到,
定義:觀察者模式定義了一種一對多的依賴關系,讓多個觀察者物件同時監聽某一個主題物件,當這些主題物件在狀態發送變化時,就會通知所有的觀察者物件,使他們能夠自動更新自己,做自己受到變化通知后想調整的邏輯狀態,
當我們將一個系統分割成一系列互相協作的類時會因為需要維護相關物件間的一致性(因一個主題變化而變化)而使得各類間緊密耦合,這樣會給維護、擴展、重用都帶來不便,這時候當一個物件的改變需要同時改變其他物件且不清楚具體有多少物件需要改變時,最佳方法便是觀察者模式來,解除耦合,
而當需要變化的觀察者已經被封裝為一個個控制元件,無法實作觀察者介面時,我們就需要通過事件委托(java中是監聽器)來實作觀察者模式,
抽象工廠模式
工廠方法模式適合少數幾個產品系列問題,當要解決涉及多個產品系列問題是,要用抽象工廠模式,
例子:資料庫訪問(有mysql,Oracle等不同的資料庫型別)
提供一個創建一系列(該抽象工廠里面提供了創建一系列的產品的抽象方法,注意是一系列產品)相關或相互依賴物件的介面,而無需指定他們具體的類,抽象工廠和工廠方法的區別便是抽象工廠創建的產品是涉及多個的,而工廠方法不是,
可以用簡單工廠模式替換抽象工廠模式,就是在簡單工廠里加判斷該實作哪一類物件switch...case模式,
而且我們可以在使用簡單工廠模式的地方考慮用反射技術來去除switch 或if ,解除分支判斷帶來的耦合,因為反射時可以用變數來決定要運行時實體化的物件,這樣就可以用傳入的變數來決定要實體化的分支,(注意:要學習下怎么在簡單工廠上加反射)
勉勵
無癡迷,不成功 ,一個程式員如果從來沒有熬夜寫程式的經歷,就不能算是一個好程式員,因為他沒有癡迷過,所以他不會有大成就,確實,成就和投入的經歷和時間成正比,
狀態模式
遵循單一職責原則、開發關閉原則
面向物件設計其實就是希望做到代碼的責任分解,
使用時有個類包含了狀態抽象類參考(作業類),各種不同的子類狀態分別對應不同的行為處理(不同作業狀態)
例子:上班狀態,不同的狀態不同的行為效率,軍隊上不同號角表示的不同戰備警備狀態,對于不同的處理方式,
定義:當一個物件的內在狀態改變時允許改變其行為,這個物件看起來像是改變了其類,
主要解決的是當控制一個物件狀態轉換的條件運算式過于復雜時,就把狀態的判斷邏輯轉移到表示不同狀態的一系列類當中,這樣把復雜的判斷邏輯簡化(到各個類中),
這樣可以將特定狀態相關的行為區域化,并吧不同狀態的行為分割開來,消除了龐大的條件分支陳述句,
當一個物件的行為取決于它的狀態,并且它必須在運行時刻根據狀態改變他的行為時,使用狀態模式,
配接器模式
例子:電源配接器(改變電壓使得符合國內220V標準);翻譯;可調節高度座椅,
在我們不能改變呼叫對接介面的雙方的前提下,我們能做的就是想辦法找個配接器,一般如兩個公司系統間的資料和行為都正確,但介面不符時的對接,
定義:將一個類的介面轉換成客戶希望的另外一個介面,配接器模式使得原本由于介面不兼容而不能一起作業的那些類可以一起作業,
簡單說就是需要的東西就在眼前,但卻不能使用,短時間無法改造它,于是想辦法適配是最好的選擇,
類配接器模式(需要通過多重繼承來對兩個介面進行匹配,不適合java等單繼承語言)和物件配接器模式(主要是這個),
配接器模式中,通過用適配類繼承目標類,即客戶端想呼叫的類來實作適配,適配類內部包裝了被適配的私有物件,在呼叫方法中實際是通過私有物件呼叫想要的方法,適用于雙方都不太容易修改的時候再使用配接器模式適配,
配接器模式主要用于軟體維護中因功能類似而介面不同時所用的無奈之舉,亡羊補牢,有點像扁鵲說自己的醫術,如果是在設計階段,應該考慮的不是適配,而是通過重構統一介面,
備忘錄模式
例子:游戲進度保存;復制粘貼,網頁前進后退這種頻繁而簡單的恢復保存在記憶體中;會議紀要,
定義:在不破壞封裝性的前提下,捕獲一個物件的內部狀態,并在該物件之外保存這個狀態,這樣以后就可以將該物件恢復到原先保存的狀態,
備忘錄模式中,需要保存狀態的物件我們叫發起者,我們會定義一個備忘錄類,發起者類上會定義一個保存狀態到備忘錄類的方法及相應提前狀態方法,備忘錄類負責存盤發起者的狀態(不提供get/set),把要保持的細節都封裝在備忘錄類上,再有一個便是備忘錄類管理者(提供備忘錄類物件的get/set方法),負責保存備忘錄類和提高備忘錄類給發起者,
備忘錄模式適合功能比較復雜,需要維護和記錄屬性歷史的類,用于還原備份的資訊到前一狀態,還有在使用命令模式時,需要實作命令的撤銷功能時,可以使用備忘錄模式存盤可撤銷操作的狀態,
缺點:如果要備份的狀態資料很大很多時,備忘錄物件會非常消耗記憶體資源,
組合模式
定義:將物件組合成樹形結構以表示 部分-整體 的層次結構,組合模式使得用戶對單個物件和組合物件的使用具有一致性,
和HeadFirst設計模式(中文版)中說的組合模式描述不太相同,待確認,我的理解一般一個組件或者類中集合了其他功能組件最后就組合成了一個功能,這就是一種組合模式,如各個零部件組合成了手機,
當需求中體現部分和整體層次的結構時,希望用戶可以忽略組合物件與單個物件的不同,統一地使用組合結構中的所以物件時,考慮使用組合模式,
使用組合模式,用戶不要關心到底是處理一個葉節點還是處理一個組合組件,也就用不著為定義組合而寫一些選擇判斷陳述句了,即組合模式讓客戶可以一致地使用組合結構和單個物件,
待對比!!!
迭代器模式
例子:售票員售票,不管是人是物,只要上次就要買票,java里的迭代器遍歷各種資料結構.foreach;iterator
定義:提供一種方法順序訪問一個聚合物件(資料結構集合)中各個元素,而又不暴露該物件的內部表示,(什么叫內部表示?)
當我們需要訪問一個聚集物件,而且不管這些物件是什么都需要遍歷的時候,應該考慮用迭代器模式,
迭代器模式即一個聚集抽象類,一個跌倒抽象類,在具體繼承的聚集類里有個創建迭代器的方法,而在具體的迭代器里有對應聚集類的具體迭代器類,并定義了一個具體聚集物件的屬性,用于在重寫迭代器方法時用具體物件來完成相應的方法,
迭代器模式分離了集合物件的遍歷行為,抽象出一個迭代器類來負責,這樣既可以做到不暴露集合的內部結構,又可以讓外部代碼透明地訪問集合內部的資料,
單例模式
例子:只要一個資料庫連接池;只要一個賴榮鋒;只要一個創造工廠;
單例模式是否實體化應該由單例物件自身判斷,通過構造方法私有來實作,不過現在java單例模式的寫法一般是通過延遲初始化占位類模式來實作,
定義:保證一個類僅有一個實體,并提供一個訪問它的全域訪問點,
防止一個類實體化多個物件的最好辦法是讓類自身負責保存它的唯一實體,
一般單例類提供私有化的建構式,并提供公有化靜態方法來獲取物件,去創建或訪問單例類的唯一實體,
多執行緒時用雙重檢查加鎖或者延遲初始化占位類模式來實作,一般用延遲初始化占位類模式比較好,
橋接模式
利用的原則是:合成(組合)/聚合復用原則,即優先使用物件合成/聚合,而不是類繼承,大雁和它的翅膀是合成或者說叫組合關系,而大雁和雁群是聚合關系,兩者之間的區別是強擁有和弱擁有的關系,組合體現了嚴格的部分和整體的關系,部分和整體的生命周期一樣,而聚合是指雁群可以保護大雁,但大雁并不是雁群的一部分,可以很輕松地脫離關系,
優先使用物件的合成聚合有助于保持每個類被封裝,并被集中在單個任務上,使得類與類繼承層次保持較小規模,
面向介面編程,通過介面組裝出想要的功能,繼承太笨重,
定義:將抽象部分與他的實作部分分離,使它們都可以獨立地變化,
兩個抽象類之間有一條聚合線,像一座橋,所以叫橋接模式,
橋接模式是由于一個物件或者說功能的實作方式有很多種,如手機可以按品牌來分實作,也可以按照功能來分,而橋接模式的核心意圖就是把這些實作獨立出來,讓他們各自地變化,這樣就使得實作的變化不會影響其他實作,達到開發關閉的拓展原則,得以應對后續的變化,
如手機,有功能抽象類,下面有通訊錄,照相機等功能實作,還有品牌抽象類,下面有蘋果,小米等實作,在如蘋果的實作類中其有設定功能抽象類進來的入參,使得蘋果可以聚合通訊錄,照相機等功能,而后面不管添加新的品牌或者功能,都只需要在各種中擴展即可,不需要重復,
當實作系統可能有多角度分類,每一種分類都有可能變化,那么就可以把這種多角度分離出來讓他們獨立變化,減少他們之間的耦合,也就是橋接模式,
例子:手機的功能和品牌區分,汽車的品牌和使用的驅動燃料不同的區分,
命令模式
例子:餐廳點餐;軍隊指揮,司令員通過通訊兵傳達資訊命令,
適用場景:當行為請求者和行為實作者緊耦合,且對請求排隊或記錄請求日志,以及支持可撤銷的操作等行為時,
定義:將一個請求封裝為一個物件,從而使你可以用不同的請求對客戶進行引數化(什么意思?);對請求排隊或記錄請求日志,以及支持可撤銷的操作,
一般是客戶端通過一個專門的呼叫者如服務員(包含一個命令集List)發出命令,命令類介面底下實作各種命令類(包含一個接受者物件),而每個具體的命令類對應有接收命令的執行者,接受命令的執行者類做出真正的動作,
優點:
- 能較容易地設計一個命令佇列
- 在需要的情況下,可以較容易地將命令記入日志
- 允許接收請求的一方決定是否要否決請求
- 可以容易地實作對請求的撤銷和重做
- 可以不影響其他類加入新的具體命令類
- 解耦,命令模式把請求一個操作的物件與知道怎么執行一個操作的物件分割開,
其他:敏捷開發原則告訴我們,不要為代碼添加基于猜測的、實際不需要的功能,
職責鏈模式
定義:使多個物件都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關系,將這個物件連成一條鏈,并沿著這條鏈傳遞該請求,知道有一個物件處理它為止,
定義一個職責類handler介面,具體的處理類實作該介面,處理它負責的請求,每個具體的處理類都會有個后繼者屬性set進來,如果是可以處理的請求則處理掉,如不不是則將該請求轉發給set進來的后繼者去處理,后繼者就是另一個具體的處理類,這樣一直請求下去,
好處:當客戶提交一個請求時,請求是沿著請求鏈傳遞直至有一個具體的處理類物件福州處理它,接受者和發送者都沒有對方的明確資訊,簡化了職責鏈可簡化物件的相互連接,因為它只需要保持一個指向其后繼者的參考,而不需要保持所以的候選接受者的參考,極大降低了耦合度,
中介者模式
又叫調停者模式
例子:房產中介;簽證中介;二手車中介;聯合國;計算器中通過form表單作為中介者來完成控制元件的互動,
前提:大量的連接使得一個物件不可能在沒有其他物件的支持下作業,系統表現為一個不可分割的整體,而這樣對系統的行為進行任何較大的改動就比較困難,因此有個同一個連接中介可以大大減少大量的連接,通過連接這個中介物件便能獲得想要的所有連接(如國與國之間通過聯合國發生關系),豈不美哉.哈哈哈哈哈哈哈哈哈哈(迪米特原則)
通過中介者物件,可以將系統的網狀結構變成以中介者為中心的星形結構,
定義:用一個中介物件來封裝一系列的物件互動,中介者使各物件不需要顯式地相互參考,從而使其耦合松散,而且可以獨立地改變它們之間的互動,
一般定義一個中介者抽象類和一個同事抽象類,具體中介者基礎該中介者抽象類,里面包含所有的同事屬性,通過set方法set進來,并實作抽象類中用來互動的抽象訊息發送方法;而具體同事類則實作同事抽象類,通過構造方法引數在創建同事類時把中介者物件添加進來,并提供發送和接收訊息的方法,
在具體實踐中,中介者類是否要抽象或者介面取決于未來是否需要擴展中介者物件,比如聯合國除了安理會還有世界衛生組織,教科文組織等,
當系統出現了 “多對多” 互動復雜的物件群時,不要急于使用中介者模式,而要先反思你的系統在設計上是不是合理,
優點:減少了各個同事類的耦合,使得可以獨立的修改和復用各個同事類和中介者類;使得我們可以站在更宏觀的角度去看系統,由于把物件如何協作進行了抽象,將中介作為一個獨立的概念并將其封裝在一個物件中,這樣關注的物件就從物件各種本身的行為轉移到天明直接的互動上來,從無數的雙邊關系轉移到聯合國關系上來,
缺點:由于中介者類控制集中化,于是就把互動復雜性變成了中介者的復雜性,使得中介者復雜度直線升高,
優點來著集中控制,缺點也來著集中控制,所以使用該模式時要考慮清楚,
一般應用于一組物件已定義良好但是互動通信復雜的場合,或者是想定制一個分布在多個類中的行為,而又不行生成太多的子類的場合(其實就是通過組合參考該行為功能吧?),
享元模式
例子:博客網站;微博;郵箱;電商;字串String;圍棋、五子棋、跳棋(大量的棋子物件,使用享元最合適不過,如圍棋創建兩個黑白棋子的享元物件,外部狀態為方位坐標)
定義:運用共享技術有效地支持大量細粒度的物件,
使用時會創建一個享元工廠,享元工廠里有個保存享元物件的hashtable集,讓用戶通過key/value形式獲取享元物件,用來創建享元物件(Flyweight),一個享元抽象類,具體有實際的享元類,和不分享的實體享元類,客戶端通過呼叫享元工廠獲得享元物件,享元工廠在創建享元物件時通過引數傳入外部狀態,
內外部狀態:在享元物件內部并且不會隨環境改變而改變的共享部分,為享元物件的內部狀態;
隨環境改變而改變、不可以共享的狀態就是外部狀態了,
享元模式可以避免大量非常相似類的開銷,在程式設計中,有時需要生成大量細粒度的類實體來表示資料,如果能發現這些實體除了幾個引數外基本上都是相同的,使用享元模式便能夠大幅度地減少需要實體化的類的數量,如果能把不同的地方一道類實體外面,在方法呼叫時將它們傳遞進來,就可以用通過共享大幅度地減少單個實施例的數目,
適用場景:如果一個應用程式使用了大量的物件,而大量的這些物件造成了很大的存盤開銷時就應該考慮使用;還有就是物件的大多數狀態可以外部狀態,如果洗掉物件的外部狀態,那么可以用相對較少的共享物件取代很多組物件,此時可以考慮使用享元模式,直觀體現便是使用享元模式,實體總數大大減少了,
解釋器模式
例子:不同瀏覽器解釋HTML語言展示頁面;正則運算式;樂譜演奏解釋器;java虛擬機解釋器;
定義:給定一個語言,定義他的文法的一種表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子,
如果一種特定型別的問題發生的頻率足夠高,那么可能就值得將該問題的各個實體表述為一個簡單語言中的句子,這樣就可以構建一個解釋器,該解釋器通過解釋這些句子來解決該問題,
一般是一個context類存放要解釋的內容,一個抽象運算式類,包括解釋和執行兩個方法,通過簡單功能加反射來決定具體選擇哪種具體運算式類解釋執行,
用解釋器模式,相當于開發了一個編程語言或腳本給自己或別人用,解釋器模式就是用 ‘迷你語言’ 來表現程式要解決的問題,以迷你語言寫成 ‘迷你程式’ 來表現具體的問題,
當有一個語言需要解釋執行,并且你可以將該語言中的句子表示為一個抽象語法樹時(?),可使用解釋器模式,
只要是可以用語言來描述的,都可以應用解釋器模式,
優點:容易改變和擴展文法,因為該模式使用類來表示文法規則,我們可以使用繼承來改變或擴展該文法;也比較容易實作文法,因為定義抽象語法樹中各個節點的類的實作大體類似,這些類都易于直接撰寫,
缺點:因為解釋器為文法中的每一條規則至少定義了一個類,因此包含許多規則的文法可能難以管理和維護,
所以當文法非常復雜時,使用語法分析程式或編譯器生成器來代替處理,
訪問者模式
定義:表示一個作用于某物件結構中的各元素的操作,它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作,
訪問者模式使用時必須確定element元素是確定的,這樣才能在狀態(visitor)類上定義確定個數element的方法,一個抽象的element類,他有一個接受狀態(visitor)引數的方法,底下具體實作如男人、女兒這樣確定的具體元素,還有一個抽象的狀態visitor類,他有對應不同元素的抽象方法,如男人的反應、女人的反應兩個方法,具體的狀態實作該抽象分別寫出不同狀態下男女不同的反應,另外有個物件結構(ObjectStructure),用于不同元素對應的邏輯展示,如針對不同的 ’狀態‘ 遍歷 男人 和 女人 ,得到不同的反應,客戶端通過物件結構,添加元素如男人、女人,然后創建不同的狀態,作為引數傳遞給物件結構展示方法,展示方法把狀態作為引數傳遞給男人、女人,讓男人女人通過接受這個方法加狀態引數來呼叫各自男女不同的方法,
訪問者模式適用于資料結構相對穩定的系統,它吧書畫家結構和作用于結構上的操作之間的耦合解開,使得操作計劃可以相對自由地演化,
目的:把處理從資料結構中分離出來,使得演算法操作的增加變得容易,當有比較穩定的資料結構,又有易于變化的演算法的話,使用訪問者模式是比較合適的,
優點:增加新的操作很容易,因為增加新的操作意味著只要增加一個新的訪問者,訪問者模式將有關的行為集中到一個訪問者物件中,
缺點:增加新的資料結構變得困難,大多數情況下很難找到資料結構不變化的情況,因此很少使用訪問者模式
給各個設計模式加上UML圖及再學習下第一章中UML圖怎么使用,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/29329.html
標籤:設計模式
