1. 程式人生 > >十種常用的設計模式(大部分自己總結,部分摘抄)

十種常用的設計模式(大部分自己總結,部分摘抄)

設計模式總結

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)行為由父類控制,由子類實現。

 缺點:

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