十種常用的設計模式

轉自:dean_hu

設計模式總結

1.       單例模式

實現方式:

a) 將被實現的類的構造方法設計成private的。

b) 添加此類引用的靜態成員變量,併爲其實例化。

c)  在被實現的類中提供公共的CreateInstance函數,返回實例化的此類,就是b中的靜態成員變量。

 

應用場景:

優點: 
    1.在單例模式中,活動的單例只有一個實例,對單例類的所有實例化得到的都是相同的一個實例。這樣就 防止其它對象對自己的實例化,確保所有的對象都訪問一個實例 
    2.單例模式具有一定的伸縮性,類自己來控制實例化進程,類就在改變實例化進程上有相應的伸縮性。 
    3.提供了對唯一實例的受控訪問。 
    4.由於在系統內存中只存在一個對象,因此可以 節約系統資源,當 需要頻繁創建和銷燬的對象時單例模式無疑可以提高系統的性能。 
    5.允許可變數目的實例。 
    6.避免對共享資源的多重佔用。 
缺點: 
    1.不適用於變化的對象,如果同一類型的對象總是要在不同的用例場景發生變化,單例就會引起數據的錯誤,不能保存彼此的狀態。 
    2.由於單利模式中沒有抽象層,因此單例類的擴展有很大的困難。 
    3.單例類的職責過重,在一定程度上違背了“單一職責原則”。 
    4.濫用單例將帶來一些負面問題,如爲了節省資源將數據庫連接池對象設計爲的單例類,可能會導致共享連接池對象的程序過多而出現連接池溢出;如果實例化的對象長時間不被利用,系統會認爲是垃圾而被回收,這將導致對象狀態的丟失。 
使用注意事項: 
    1.使用時不能用反射模式創建單例,否則會實例化一個新的對象 
    2.使用懶單例模式時注意線程安全問題 
    3.單例模式和懶單例模式構造方法都是私有的,因而是不能被繼承的,有些單例模式可以被繼承(如登記式模式) 
適用場景: 
    單例模式只允許創建一個對象,因此節省內存,加快對象訪問速度,因此對象需要被公用的場合適合使用,如多個模塊使用同一個數據源連接對象等等。如: 
    1.需要頻繁實例化然後銷燬的對象。 
    2.創建對象時耗時過多或者耗資源過多,但又經常用到的對象。 
    3.有狀態的工具類對象。 
    4.頻繁訪問數據庫或文件的對象。 
以下都是單例模式的經典使用場景: 
    1.資源共享的情況下,避免由於資源操作時導致的性能或損耗等。如上述中的日誌文件,應用配置。 
    2.控制資源的情況下,方便資源之間的互相通信。如線程池等。 
應用場景舉例: 
    1.外部資源:每臺計算機有若干個打印機,但只能有一個PrinterSpooler,以避免兩個打印作業同時輸出到打印機。內部資源:大多數軟件都有一個(或多個)屬性文件存放系統配置,這樣的系統應該有一個對象管理這些屬性文件 
    2. Windows的TaskManager(任務管理器)就是很典型的單例模式(這個很熟悉吧),想想看,是不是呢,你能打開兩個windows task manager嗎? 不信你自己試試看哦~ 
    3. windows的Recycle Bin(回收站)也是典型的單例應用。在整個系統運行過程中,回收站一直維護着僅有的一個實例。 
    4. 網站的計數器,一般也是採用單例模式實現,否則難以同步。 
    5. 應用程序的日誌應用,一般都何用單例模式實現,這一般是由於共享的日誌文件一直處於打開狀態,因爲只能有一個實例去操作,否則內容不好追加。 
    6. Web應用的配置對象的讀取,一般也應用單例模式,這個是由於配置文件是共享的資源。 
    7. 數據庫連接池的設計一般也是採用單例模式,因爲數據庫連接是一種數據庫資源。數據庫軟件系統中使用數據庫連接池,主要是節省打開或者關閉數據庫連接所引起的效率損耗,這種效率上的損耗還是非常昂貴的,因爲何用單例模式來維護,就可以大大降低這種損耗。 
    8. 多線程的線程池的設計一般也是採用單例模式,這是由於線程池要方便對池中的線程進行控制。 
    9. 操作系統的文件系統,也是大的單例模式實現的具體例子,一個操作系統只能有一個文件系統。 
    10. HttpApplication 也是單位例的典型應用。熟悉ASP.Net(IIS)的整個請求生命週期的人應該知道HttpApplication也是單例模式,所有的HttpModule都共享一個HttpApplication實例. 

 

2.       策略模式

實現方式:

a)      提供公共接口或抽象類,定義需要使用的策略方法。(策略抽象類)

b)      多個實現的策略抽象類的實現類。(策略實現類)

c)       環境類,對多個實現類的封裝,提供接口類型的成員量,可以在客戶端中切換。

d)      客戶端 調用環境類 進行不同策略的切換。

注:Jdk中的TreeSet TreeMap的排序功能就是使用了策略模式。


策略模式的優點

  (1)策略模式提供了管理相關的算法族的辦法。策略類的等級結構定義了一個算法或行爲族。恰當使用繼承可以把公共的代碼移到父類裏面,從而避免代碼重複。

  (2)使用策略模式可以避免使用多重條件(if-else)語句。多重條件語句不易維護,它把採取哪一種算法或採取哪一種行爲的邏輯與算法或行爲的邏輯混合在一起,統統列在一個多重條件語句裏面,比使用繼承的辦法還要原始和落後。

策略模式的缺點

  (1)客戶端必須知道所有的策略類,並自行決定使用哪一個策略類。這就意味着客戶端必須理解這些算法的區別,以便適時選擇恰當的算法類。換言之,策略模式只適用於客戶端知道算法或行爲的情況。

  (2)由於策略模式把每個具體的策略實現都單獨封裝成爲類,如果備選的策略很多的話,那麼對象的數目就會很可觀。

 

3.       代理模式
一)靜態代理

實現方式:

a) 爲真實類和代理類提供的公共接口或抽象類。(租房)

b) 真實類,具體實現邏輯,實現或繼承a。(房主向外租房)

c)  代理類,實現或繼承a,有對b的引用,調用真實類的具體實現。(中介)

d) 客戶端,調用代理類實現對真實類的調用。(租客租房)

二)動態代理

實現方式:

a) 公共的接口(必須是接口,因爲Proxy類的newproxyinstance方法的第二參數必須是個接口類型的Class)

b) 多個真實類,具體實現的業務邏輯。

c)  代理類,實現InvocationHandler接口,提供Object成員變量,和Set方法,便於客戶端切換。

d) 客戶端,獲得代理類的實例,爲object實例賦值,調用Proxy.newproxyinstance方法在程序運行時生成繼承公共接口的實例,調用相應方法,此時方法的執行由代理類實現的Invoke方法接管。


jdk動態代理使用的侷限性
通過反射類ProxyInvocationHandler回調接口實現的jdk動態代理,要求委託類必須實現一個接口,但事實上並不是所有類都有接口,對於沒有實現接口的類,便無法使用該方方式實現動態代理。

 

4.       觀察者模式

觀察者模式是對象的行爲模式,又叫發佈-訂閱(Publish/Subscribe)模式、模型-視圖(Model/View)模式、源-監聽器(Source/Listener)模式或從屬者(Dependents)模式。

實現方式:

a) 角色抽象類(提供對觀察者的添加,刪除和通知功能)。

b) 角色具體類,實現a,維護一個c的集合(對角色抽象類的實現)。

c)  觀察者抽象類(被角色通知後實現的方法)。

d) 觀察者實現類,實現c(多個)。

注:JDK提供了對觀察者模式的支持,使用Observable類和Observer接口


兩種模型(推模型和拉模型):

■  推模型是假定主題對象知道觀察者需要的數據;而拉模型是主題對象不知道觀察者具體需要什麼數據,沒有辦法的情況下,乾脆把自身傳遞給觀察者,讓觀察者自己去按需要取值。

■  推模型可能會使得觀察者對象難以複用,因爲觀察者的update()方法是按需要定義的參數,可能無法兼顧沒有考慮到的使用情況。這就意味着出現新情況的時候,就可能提供新的update()方法,或者是乾脆重新實現觀察者;而拉模型就不會造成這樣的情況,因爲拉模型下,update()方法的參數是主題對象本身,這基本上是主題對象能傳遞的最大數據集合了,基本上可以適應各種情況的需要。

  

 

5.       裝飾模式:

實現方式:

a)       抽象的被裝飾角色 (所有的角色都要直接或間接的實現本角色)

b)       具體的被裝飾角色,實現或繼承a (被功能擴展的角色)

c)       裝飾角色,實現或繼承a (本類有對a的引用,所有的具體裝飾角色都需要繼承這個角色)

d)       多個具體修飾角色 ,繼承c(對被裝飾角色的功能擴展,可以任意搭配使用)


意圖: 

動態地給一個對象添加一些額外的職責。就增加功能來說,Decorator模式相比生成子類更爲靈活。該模式以對客 戶端透明的方式擴展對象的功能。

適用環境:

(1)在不影響其他對象的情況下,以動態、透明的方式給單個對象添加職責。

(2)處理那些可以撤消的職責。

(3)當不能採用生成子類的方法進行擴充時。一種情況是,可能有大量獨立的擴展,爲支持每一種組合將產生大量的 子類,使得子類數目呈爆炸性增長。另一種情況可能是因爲類定義被隱藏,或類定義不能用於生成子類。

  

6.      適配器模式:

適配器模式把一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作。

1.       類適配器(子類繼承方式)

實現方式:

a)     目標抽象角色(定義客戶要用的接口)

b)     適配器(實現a繼承c,作爲一個轉換器被客戶調用)

c)     待適配器(真正需要被調用的)

d)     客戶端(借用a的實例調用c的方法)


2.     對象適配器(對象的組合方式)

實現方式:

a)     目標抽象角色(定義客戶要用的接口)

b)     適配器(實現a,維護一個c的引用,作爲一個轉換器被d調用)

c)     待適配器(真正需要被調用的)

d)     客戶端(此類,借用a類的實例調用c類的方法,類似靜態代理,但是解決的問題不同)


3.     缺省的方式

實現方式:

a)     抽象接口

b)     實現a的適配器類(空實現)

c)     客戶端,繼承b,調用b中的方法,不必直接實現a(直接實現a需要實現a中的所有的方法)

適配器模式的優點:

1.     更好的複用性

  系統需要使用現有的類,而此類的接口不符合系統的需要。那麼通過適配器模式就可以讓這些功能得到更好的複用。

2.     更好的擴展性

在實現適配器功能的時候,可以調用自己開發的功能,從而自然地擴展系統的功能。

適配器模式的缺點:

  過多的使用適配器,會讓系統非常零亂,不易整體進行把握。比如,明明看到調用的是A接口,其實內部被適配成了B接口的實現,一個系統如果太多出現這種情況,無異於一場災難。因此如果不是很有必要,可以不使用適配器,而是直接對系統進行重構。

 

 

7.    命令模式

將一個請求封裝爲一個對象,從而可用不同的請求對客戶進行參數化;對請求排隊或記錄日誌,以及支持可撤銷的操作

將“發出請求的對象”和”接收與執行這些請求的對象”分隔開來。

實現方式:

a)     抽象的命令角色 , 如:菜單(規定可以點哪些菜)

b)     具體的命令角色(實現a 維護一個對c的引用),如:訂單(已點的菜)

c)     接收者(具體執行命令的角色),實際操作時,很常見使用"聰明"命令對象,也就是直接實現了請求,而不是將工作委託給c (弊端?) 如:廚師接收訂單後做菜

d)     調用者(維護一個對a的引用),如:服務員負責點菜並把訂單推給廚師

e)     客戶端 調用d發出命令進而執行c的方法,如:顧客點餐

 

效果:
1)、command模式將調用操作的對象和實現該操作的對象解耦
2)、可以將多個命令裝配成一個複合命令,複合命令是Composite模式的一個實例
3)、增加新的command很容易,無需改變已有的類
適用性:
1)、抽象出待執行的動作以參數化某對象
2)、在不同的時刻指定、排列和執行請求。如請求隊列
3)、支持取消操作
4)、支持修改日誌
5)、用構建在原語操作上的高層操作構造一個系統。支持事物


8.    組合模式

將對象組合成樹形結構以表示“部分整體”的層次結構。組合模式使得用戶對單個對象和複雜對象的使用具有一致性。

實現方式:

a)     抽象的構件接口 (規範執行的方法),b及c都需實現此接口,如:Junit中的Test接口

b)     葉部件(實現a,最小的執行單位),如:Junit中我們所編寫的測試用例

c)     組合類(實現a並維護一個a的集合[多個b的組合]),如:Junit中的 TestSuite

d)     客戶端 可以隨意的將b和c進行組合,進行調用

 

什麼情況下使用組合模式:

當發現需求中是體現部分與整體層次結構時,以及你希望用戶可以忽略組合對象與單個對象的不同,統一地使用組合結構中的所有對象時,就應該考慮組合模式了。

 

 

 

 

 

 

9.    簡單工廠模式

就是建立一個工廠類,對實現了同一接口的一些類進行實例的創建。簡單工廠模式的實質是由一個工廠類根據傳入的參數,動態決定應該創建哪一個產品類(這些產品類繼承自一個父類或接口)的實例。

實現方式:

a)     抽象產品類(也可以是接口)

b)     多個具體的產品類

c)     工廠類(包括創建a的實例的方法)

 

優點:

工廠類是整個模式的關鍵.包含了必要的邏輯判斷,根據外界給定的信息,決定究竟應該創建哪個具體類的對象.通過使用工廠類,外界可以從直接創建具體產品對象的尷尬局面擺脫出來,僅僅需要負責消費對象就可以了。而不必管這些對象究竟如何創建及如何組織的.明確了各自的職責和權利,有利於整個軟件體系結構的優化。

   

缺點:

由於工廠類集中了所有實例的創建邏輯,違反了高內聚責任分配原則,將全部創建邏輯集中到了一個工廠類中;它所能創建的類只能是事先考慮到的,如果需要添加新的類,則就需要改變工廠類了。當系統中的具體產品類不斷增多時候,可能會出現要求工廠類根據不同條件創建不同實例的需求.這種對條件的判斷和對具體產品類型的判斷交錯在一起,很難避免模塊功能的蔓延,對系統的維護和擴展非常不利;

 

  

10. 模板方法模式

實現方式:

a)     父類模板類(規定要執行的方法和順序,只關心方法的定義及順序,不關心方法實現)

b)     子類實現類(實現a規定要執行的方法,只關心方法實現,不關心調用順序)



 

 優點:

        1)封裝不變部分,擴展可變部分:把認爲不變部分的算法封裝到父類實現,可變部分則可以通過繼承來實現,很容易擴展。

        2)提取公共部分代碼,便於維護。

       3)行爲由父類控制,由子類實現。

 缺點:

        模板方法模式顛倒了我們平常的設計習慣:抽象類負責聲明最抽象、最一般的事物屬性和方法,實現類實現具體的事物屬性和方法。在複雜的項目中可能會帶來代碼閱讀的難度。


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