GoF: 必背 24種設計模式 : 設計原則: 設計模式(總綱) 創建型(6): 單例模式 簡單工廠模式 工廠方法模式 抽象工廠模式 建造者模式 原型模式 結構型(7 ,2個器,5個兩字的): 代理模式 適配器模式 裝飾器模式 橋接模式 組合模式 享元模式 外觀模式 行為型(11): 觀察者模式 模 ...
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圖怎麼使用。