標籤:裝飾模式 提高效率 代碼 nis 釋放 懶漢式 pop 智能 dip
一、內容題綱
- 設計模式概念
- 設計模式分類
- 設計模式原則
- 單例模式
- 多例模式
- 原廠模式
- 代理模式
- 原型模式
二、具體內容
- 設計模式概念
設計模式(Design pattern)是一套被反覆使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。
毫無疑問,設計模式於己於他人於系統都是多贏的;設計模式使代碼編製真正工程化;設計模式是軟體工程的基石脈絡,如同大廈的結構一樣。
提倡使用設計模式的根本原因是代碼複用,增加可維護性。
- 設計模式分類
設計模式分為三種類型,共23種。
建立型模式(5):單例模式、抽象原廠模式、建造者模式、原廠模式、原型模式。
結構型模式(7):適配器模式、橋接模式、裝飾模式、組合模式、面板模式、享元模式、代理模式。
行為型模式(11):模版方法模式、命令模式、迭代器模式、觀察者模式、中介者模式、備忘錄模式、解譯器模式、狀態模式、策略模式、職責鏈模式、訪問者模式。
- 設計模式原則
為什麼要提倡“Design Pattern呢?根本原因是為了代碼複用,增加可維護性。那麼怎麼才能實現代碼複用呢?
物件導向有幾個原則:
單一職責原則 (Single Responsiblity Principle SRP)
開閉原則(Open Closed Principle,OCP)、
裡氏代換原則(Liskov Substitution Principle,LSP)、
依賴倒轉原則(Dependency Inversion Principle,DIP)、
介面隔離原則(Interface Segregation Principle,ISP)、合成/彙總複用原則(Composite/Aggregate Reuse Principle,CARP)、最小知識原則(Principle of Least Knowledge,PLK,也叫迪米特法則)。開閉原則具有理想主義的色彩,它是物件導向設計的終極目標。其他幾條,則可以看做是開閉原則的實現方法。
設計模式就是實現了這些原則,從而達到了代碼複用、增加可維護性的目的。
- 單例模式
概念
數學與邏輯學中,singleton定義為“有且僅有一個元素的集合”。
單例模式最初的定義出現於《設計模式》(艾迪生維斯理,1994):“保證一個類僅有一個執行個體,並提供一個訪問它的全域訪問點。”
Java中單例模式定義:“一個類有且僅有一個執行個體,並且自行執行個體化向整個系統提供。”
我們可以理解為:保證一個類僅有一個執行個體,並提供一個訪問它的全域訪問點。
適用性
當類只能有一個執行個體而且客戶可以從一個眾所周知的訪問點訪問它時。
當這個唯一執行個體應該是通過子類化可擴充的,並且客戶應該無需更改代碼就能使用一個擴充的執行個體時。
單例模式有以下特點:
1、單例類只能有一個執行個體。
2、單例類必須自己建立自己的唯一執行個體。
3、單例類必須給所有其他對象提供這一執行個體。
單例模式的好處就是:
類只執行個體化一次,省資源,節省開銷,提高速度
單例模式分類
建立單例有兩種模式,一種是餓漢模式,一種是懶漢模式,具體代碼如下:
/**
* 單例模式 餓漢模式
* @author <wpda
* 應用場合:只需要一個就足夠了
* 作用:保證整個程式中某個執行個體有且只有一個
*/
public class Starving {
//1.將構造方法私人化,不允許外部直接建立對象
private Starving(){
}
//2.建立類的唯一執行個體
private static Starving instance = new Starving();
//提供一個用於擷取執行個體的方法
//需要注意的是,我們這個方法屬於對象,不是類方法
//public Starving getInstance(){
//return instance;
//}
//3.提供一個用於擷取執行個體的私人的類的靜態成員方法
public static Starving getInstance(){
return instance;
}
}
/**
*單例模式 懶漢模式
* @author Administrator
*
*/
public class Lazy {
//將構造方法私人化,不循序外部直接建立對象
private Lazy(){
}
//2.聲明類的唯一執行個體
private static Lazy instance;
//3.提供一個用於擷取執行個體的方法
public static Lazy getInstance(){
if(instance == null){
instance = new Lazy();
}
return instance;
}
}
a) 餓漢模式的特點是載入類時比較慢,但運行時擷取對象的速度比較快,餓漢式是安全執行緒的,在類建立的同時就已經建立好一個靜態對象供系統使用,以後不在改變。
b) 懶漢模式的特點是載入類時比較快,但是在運行時擷取對象的速度比較慢,線程不安全,懶漢式如果在建立執行個體對象時不加上synchronized則會導致對象的訪問不是安全執行緒的。
所以在此推薦大家使用餓漢模式。
主要優點:
1、提供了對唯一執行個體的受控訪問。
2、由於在系統記憶體中只存在一個對象,因此可以節約系統資源,對於一些需要頻繁建立和銷毀的對象單例模式無疑可以提高系統的效能。
3、允許可變數目的執行個體。
主要缺點:
1、由於單利模式中沒有抽象層,因此單例類的擴充有很大的困難。
2、單例類的職責過重,在一定程度上違背了“單一職責原則”。
3、濫用單例將帶來一些負面問題,如為了節省資源將資料庫連接池對象設計為的單例類,可能會導致共用串連池對象的程式過多而出現串連池溢出;如果執行個體化的對象長時間不被利用,系統會認為是垃圾而被回收,這將導致對象狀態的丟失。
- 多例模式
一、單例模式和多例模式說明:
1). 單例模式和多例模式屬於對象模式。
2). 單例模式的對象在整個系統中只有一份,多例模式可以有多個執行個體。
3). 它們都不對外提供構造方法,即構造方法都為私人。
4). 單例模式和多例模式的結構圖如下所示:
多例模式的定義:
作為對象的建立模式,多例模式中的多例類可以有多個執行個體,而且多例類必須自己建立、管理自己的執行個體,並向外界提供自己的執行個體。
多例模式的特點:
所謂的多例模式(Multiton Pattern),實際上就是單例模式的自然推廣。作為對象的建立模式,多例模式或多例類有如下的特點:
(1)多例類可有多個執行個體
(2)多例類必須自己建立、管理自己的執行個體,並向外界提供自己的執行個體。
(3)根據是否有執行個體上限分為:有上限多例類和無上限多例類。
- 原廠模式
概念
定義一個用於建立對象的介面,讓子類決定執行個體化哪一個類。Factory Method 使一個類的執行個體化延遲到其子類。
適用性
當一個類不知道它所必須建立的對象的類的時候。
當一個類希望由它的子類來指定它所建立的對象的時候。
當類將建立對象的職責委託給多個協助子類中的某一個,並且你希望將哪一個協助子類是代理者這一資訊局部化的時候。
意圖:定義一個建立對象的介面,讓其子類自己決定執行個體化哪一個工廠類,原廠模式使其建立過程延遲到子類進行。
主要解決:主要解決介面選擇的問題。
何時使用:我們明確地計劃不同條件下建立不同執行個體時。
如何解決:讓其子類實現工廠介面,返回的也是一個抽象的產品。
關鍵代碼:建立過程在其子類執行。
應用執行個體: 1、您需要一輛汽車,可以直接從工廠裡面提貨,而不用去管這輛汽車是怎麼做出來的,以及這個汽車裡面的具體實現。 2、Hibernate 換資料庫只需換方言和驅動就可以。
優點: 1、一個調用者想建立一個對象,只要知道其名稱就可以了。 2、擴充性高,如果想增加一個產品,只要擴充一個工廠類就可以。 3、屏蔽產品的具體實現,調用者只關心產品的介面。
缺點:每次增加一個產品時,都需要增加一個具體類和對象實現工廠,使得系統中類的個數成倍增加,在一定程度上增加了系統的複雜度,同時也增加了系統具體類的依賴。這並不是什麼好事。
使用情境: 1、日誌記錄器:記錄可能記錄到本地硬碟、系統事件、遠程伺服器等,使用者可以選擇記錄日誌到什麼地方。 2、資料庫訪問,當使用者不知道最後系統採用哪一類資料庫,以及資料庫可能有變化時。 3、設計一個串連伺服器的架構,需要三個協議,"POP3"、"IMAP"、"HTTP",可以把這三個作為產品類,共同實現一個介面。
注意事項:作為一種建立類模式,在任何需要產生複雜物件的地方,都可以使用Factory 方法模式。有一點需要注意的地方就是複雜物件適合使用原廠模式,而簡單對象,特別是只需要通過 new 就可以完成建立的對象,無需使用原廠模式。如果使用原廠模式,就需要引入一個工廠類,會增加系統的複雜度。
- 代理模式
概念
為其他對象提供一種代理以控制對這個對象的訪問。
適用性
在需要用比較通用和複雜的對象指標代替簡單的指標的時候,使用Proxy模式。下面是一 些可以使用Proxy模式常見情況:
遠程代理(Remote Proxy)為一個對象在不同的地址空間提供局部代表。
虛代理(Virtual Proxy)根據需要建立開銷很大的對象。
保護代理(Protection Proxy)控制對原始對象的訪問。保護代理用於對象應該有不同的存取權限的時候。
智能指引(Smart Reference)取代了簡單的指標,它在訪問對象時執行一些附加操作。它的典型用途包括:
對指向實際對象的引用計數,這樣當該對象沒有引用時,可以自動釋放它(也稱為SmartPointers)。
當第一次引用一個持久對象時,將它裝入記憶體。
在訪問一個實際對象前,檢查是否已經鎖定了它,以確保其他對象不能改變它。
1.初識代理模式
生活中大家一定遇到這樣的情況了:比如說我要買一條毛巾,不妨就是潔麗雅的吧,那一般人的話我應該不是去潔麗雅的工廠裡面直接去買吧,而是我們在潔麗雅專賣店或者什麼超市啊,這些地方購買,這些地方實際上就是潔麗雅毛巾的代理。這其實和我們OO中的代理模式是很相似的。
一個it人士,上網應該是經常的事了吧,那麼總會有這樣的情況,開啟一個網頁,文字先出現,而那些比較大的資源,例片要等等才會顯示出來,這是為什麼呢??實際上這其中採用的就是代理模式。
2.代理模式的一個簡單的例子
就說上面的毛巾的例子吧,將有如下類圖:
3.代理模式的意義
代理模式到底好處在哪裡呢??
那先要說一下代理模式中的三種角色了。
抽象角色:聲明真實對象和代理對象的共同介面。
代理角色:代理對象角色內部含有對真實對象的引用,從而可以操作真實對象,同時代理對象提供與真實對象相同的介面以便在任何時刻都能代替真實對象。同時,代理對象 可以在執行真實對象操作時,附加其他的操作,相當於對真實對象進行封裝。
真實角色:代理角色所代表的真實對象,是我們最終要引用的對象。
代理模式的一個好處就是對外部提供統一的介面方法,而代理類在介面中實現對真實類的附加操作行為,從而可以在不影響外部調用情況下,進行系統擴充。也就是說,我要修改真實角色的操作的時候,盡量不要修改他,而是在外部在“包”一層進行附加行為,即代理類。例如:介面A有一個介面方法operator(),真實角色:RealA實現介面A,則必須實現介面方法operator()。用戶端Client調用介面A的接方法operator()。現在新需求來了,需要修改RealA中的operator()的操作行為。怎麼辦呢?如果修改RealA就會影響原有系統的穩定性,還要重新測試。這是就需要代理類實現附加行為操作。建立代理ProxyA實現介面A,並將真實對象RealA注入進來。ProxyA實現介面方法operator(),另外還可以增加附加行為,然後調用真實對象的operator()。從而達到了“對修改關閉,對擴充開放”,保證了系統的穩定性。我們看用戶端Client調用仍是介面A的介面方法operator(),只不過執行個體變為了ProxyA類了而已。也就是說代理模式實現了ocp原則。
4.什麼時候使用代理模式
當我們需要使用的對象很複雜或者需要很長時間去構造,這時就可以使用代理模式(Proxy)。例如:如果構建一個對象很耗費時間和電腦資源,代理模式(Proxy)允許我們控制這種情況,直到我們需要使用實際的對象。一個代理(Proxy)通常包含和將要使用的對象同樣的方法,一旦開始使用這個對象,這些方法將通過代理(Proxy)傳遞給實際的對象。 一些可以使用代理模式(Proxy)的情況:
一個對象,比如一幅很大的映像,需要載入的時間很長。
一個需要很長時間才可以完成的計算結果,並且需要在它計算過程中顯示中間結果
一個存在於遠端電腦上的對象,需要通過網路載入這個遠程對象則需要很長時間,特別是在網路傳輸高峰期。
一個對象只有有限存取權,代理模式(Proxy)可以驗證使用者的許可權
代理模式(Proxy)也可以被用來區別一個對象執行個體的請求和實際的訪問,例如:在程式初始化過程中可能建立多個對象,但並不都是馬上使用,代理模式(Proxy)可以載入需要的真正的對象。這是一個需要載入和顯示一幅很大的映像的程式,當程式啟動時,就必須確定要顯示的映像,但是實際的映像只能在完全載入後才可以顯示!這時我們就可以使用代理模式(Proxy)。
- 原型模式
概念
用原型執行個體指定建立對象的種類,並且通過拷貝這些原型建立新的對象。
適用性
當要執行個體化的類是在運行時刻指定時,例如,通過動態裝載;或者為了避免建立一個與產品類層次平行的工廠類層次時;或者當一個類的執行個體只能有幾個不同狀態組合中的一種時。建立相應數目的原型並複製它們可能比每次用合適的狀態手工執行個體化該類更方便一些。
講到原型模式了,我們就不得不區分兩個概念:深拷貝、淺拷貝。
淺拷貝:使用一個已知執行個體對新建立執行個體的成員變數逐個賦值,這個方式被稱為淺拷貝。
深拷貝:當一個類的拷貝構造方法,不僅要複製對象的所有非引用成員變數值,還要為參考型別的成員變數建立新的執行個體,並且初始化為形式參數執行個體值。
優點
1、如果建立新的對象比較複雜時,可以利用原型模式簡化對象的建立過程,同時也能夠提高效率。
2、可以使用深複製保持對象的狀態。
3、原型模式提供了簡化的建立結構。
缺點
1、在實現深複製的時候可能需要比較複雜的代碼。
2、需要為每一個類配備一個複製方法,而且這個複製方法需要對類的功能進行通盤考慮,這對全新的類來說不是很難,但對已有的類進行改造時,不一定是件容易的事,必須修改其原始碼,違背了“開閉原則”。
總結
1、原型模式向客戶隱藏了建立對象的複雜性。客戶只需要知道要建立對象的類型,然後通過請求就可以獲得和該對象一模一樣的新對象,無須知道具體的建立過程。
2、複製分為淺複製和深複製兩種。
3、我們雖然可以利用原型模式來獲得一個新對象,但有時對象的複製可能會相當的複雜,比如深複製。
設計模式的總結