設計模式 --創建型
范圍\目的 |
創建型模式 |
結構型模式 |
行為型模式 |
類模式 |
工廠方法模式 |
(類)適配器模式 |
解釋器模式 模板方法模式 |
對象模式 |
抽象工廠模式 建造者模式 原型模式 單例模式 |
(對象)適配器模式 橋接模式 組合模式 裝飾模式 外觀模式 享元模式 代理模式 |
職責鏈模式 命令模式 迭代器模式 中介者模式 備忘錄模式 觀察者模式 狀態模式 策略模式 訪問者模式 |
根據目的、用途的不同,分為創建性模式、結構性模式、行為性模式。創建型模式主要用於創建對象,結構型模式主要用於處理類和對象的組合,行為性模式主要用於描述類或對象的交互以及職責分配。
根據處理范圍不同,設計模式又可分為類模式和對象模式,類模式處理類與子類的關系,通過處理這些關系來建立繼承,屬於靜態關系,在編譯時候確定下來;對象模式處理對象之間的關系,運行時發生變化,屬於動態關系。
1. 創建性模式Creational(5種)
一.抽象工廠模式(對象型)
模式動機
a) 當系統所提供的工廠所需生產的具體產品並不是一個簡單的對象,而是多個位於不同產品等級結構中屬於不同類型的具體產品時需要使用抽象工廠模式。
b) 抽象工廠模式是所有形式的工廠模式中最為抽象和最具一般性的一種形態。
c) 抽象工廠模式與工廠方法模式最大的區別在於,工廠方法模式針對的是一個產品等級結構,而抽象工廠模式則需要面對多個產品等級結構,一個工廠等級結構可以負責多個不同產品等級結構中的產品對象的創建。當一個工廠等級結構可以創建出分屬於不同產品等級結構的一個產品族中的所有對象時,抽象工廠模式比工廠方法模式更為簡單、有效率。
抽象工廠模式是所有工廠模式中最為抽象,最為一般性的模式
定義:它提供一個接口,可以創建一系列相關或相互依賴的對象,而無需制定他們具體的類。
說明:抽象工廠方法引入了產品的等級結構和產品族的概念,產品的等級結構指抽象的產品與具體的產品所構成的繼承層次關系;產品族指的是同一個工廠所生產的一系列產品,也就是位於不同產品等級結構且功能相關聯的產品所組成的家族。
抽象工廠模式包含如下角色:
AbstractFactory:抽象工廠
ConcreteFactory:具體工廠
AbstractProduct:抽象產品
Product:具體產品
抽象工廠模式的優點
抽象工廠模式隔離了具體類的生成,使得客戶並不需要知道什么被創建。由於這種隔離,更換一個具體工廠就變得相對容易。所有的具體工廠都實現了抽象工廠中定義的那些公共接口,因此只需改變具體工廠的實例,就可以在某種程度上改變整個軟件系統的行為。另外,應用抽象工廠模式可以實現高內聚低耦合的設計目的,因此抽象工廠模式得到了廣泛的應用。
當一個產品族中的多個對象被設計成一起工作時,它能夠保證客戶端始終只使用同一個產品族中的對象。這對一些需要根據當前環境來決定其行為的軟件系統來說,是一種非常實用的設計模式。
增加新的具體工廠和產品族很方便,無須修改已有系統,符合“開閉原則”。
抽象工廠模式的缺點
在添加新的產品對象時,難以擴展抽象工廠來生產新種類的產品,這是因為在抽象工廠角色中規定了所有可能被創建的產品集合,要支持新種類的產品就意味着要對該接口進行擴展,而這將涉及到對抽象工廠角色及其所有子類的修改,顯然會帶來較大的不便。
開閉原則的傾斜性(增加新的工廠和產品族容易,增加新的產品等級結構麻煩)
在以下情況下可以使用抽象工廠模式:
- 一個系統不應當依賴於產品類實例如何被創建、組合和表達的細節,這對於所有類型的工廠模式都是重要的。
- 系統中有多於一個的產品族,而每次只使用其中某一產品族。
- 屬於同一個產品族的產品將在一起使用,這一約束必須在系統的設計中體現出來。
- 系統提供一個產品類的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴於具體實現。
二.工廠模式(類)
當抽象工廠退化為只有一個產品的等級結構時,就會變成工廠方法模式,整個工廠只生產一種產品,工廠方法模式是類創建模式,又叫虛擬構造器。父類是負責定義創建對象的公共接口,子類負責生成具體的對象,這樣做的目的是將類的實例化延遲到子類來進行。
定義:定義一個創建對象的接口,但由子類決定需要實例化哪個類,工廠方法使得子類實例化的過程推遲。
工廠方法模式的優點
在工廠方法模式中,工廠方法用來創建客戶所需要的產品,同時還向客戶隱藏了哪種具體產品類將被實例化這一細節,用戶只需要關心所需產品對應的工廠,無須關心創建細節,甚至無須知道具體產品類的類名。
基於工廠角色和產品角色的多態性設計是工廠方法模式的關鍵。它能夠使工廠可以自主確定創建何種產品對象,而如何創建這個對象的細節則完全封裝在具體工廠內部。工廠方法模式之所以又被稱為多態工廠模式,是因為所有的具體工廠類都具有同一抽象父類。
使用工廠方法模式的另一個優點是在系統中加入新產品時,無須修改抽象工廠和抽象產品提供的接口,無須修改客戶端,也無須修改其他的具體工廠和具體產品,而只要添加一個具體工廠和具體產品就可以了。這樣,系統的可擴展性也就變得非常好,完全符合“開閉原則”。
工廠方法模式的缺點
在添加新產品時,需要編寫新的具體產品類,而且還要提供與之對應的具體工廠類,系統中類的個數將成對增加,在一定程度上增加了系統的復雜度,有更多的類需要編譯和運行,會給系統帶來一些額外的開銷。
由於考慮到系統的可擴展性,需要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增加了系統的抽象性和理解難度,且在實現時可能需要用到DOM、反射等技術,增加了系統的實現難度。
在以下情況下可以使用工廠方法模式:
一個類不知道它所需要的對象的類:在工廠方法模式中,客戶端不需要知道具體產品類的類名,只需要知道所對應的工廠即可,具體的產品對象由具體工廠類創建;客戶端需要知道創建具體產品的工廠類。
一個類通過其子類來指定創建哪個對象:在工廠方法模式中,對於抽象工廠類只需要提供一個創建產品的接口,而由其子類來確定具體要創建的對象,利用面向對象的多態性和里氏代換原則,在程序運行時,子類對象將覆蓋父類對象,從而使得系統更容易擴展。
將創建對象的任務委托給多個工廠子類中的某一個,客戶端在使用時可以無須關心是哪一個工廠子類創建產品子類,需要時再動態指定,可將具體工廠類的類名存儲在配置文件或數據庫中。
三.建造者模式(對象型)
動機
在軟件開發中,也存在大量類似汽車一樣的復雜對象,它們擁有一系列成員屬性,這些成員屬性中有些是引用類型的成員對象。而且在這些復雜對象中,還可能存在一些限制條件,如某些屬性沒有賦值則復雜對象不能作為一個完整的產品使用;有些屬性的賦值必須按照某個順序,一個屬性沒有賦值之前,另一個屬性可能無法賦值等。
復雜對象相當於一輛有待建造的汽車,而對象的屬性相當於汽車的部件,建造產品的過程就相當於組合部件的過程。由於組合部件的過程很復雜,因此,這些部件的組合過程往往被“外部化”到一個稱作建造者的對象里,建造者返還給客戶端的是一個已經建造完畢的完整產品對象,而用戶無須關心該對象所包含的屬性以及它們的組裝方式,這就是建造者模式的模式動機。
定義:強調的是將一個復雜的對象的表示與其構造相分離,使得同樣的構建過程能夠得出不同的表示。
說明:建造者模式是一步一步地創建一個復雜的對象,它允許用戶只通過指定復雜對象的類型和內容就可以構建他們,而無需知道具體的構建細節。
建造者模式包含如下角色:
Builder:抽象建造者
ConcreteBuilder:具體建造者
Director:指揮者
Product:產品角色
建造者模式的結構中還引入了一個指揮者類Director,該類的作用主要有兩個:一方面它隔離了客戶與生產過程;另一方面它負責控制產品的生成過程。指揮者針對抽象建造者編程,客戶端只需要知道具體建造者的類型,即可通過指揮者類調用建造者的相關方法,返回一個完整的產品對象。
public class Director { private Builder builder; public Director(Builder builder) { this.builder=builder; } public void setBuilder(Builder builder) { this.builder=builer; } public Product construct() { builder.buildPartA(); builder.buildPartB(); builder.buildPartC(); return builder.getResult(); } }
建造者模式的優點
在建造者模式中,客戶端不必知道產品內部組成的細節,將產品本身與產品的創建過程解耦,使得相同的創建過程可以創建不同的產品對象。
每一個具體建造者都相對獨立,而與其他的具體建造者無關,因此可以很方便地替換具體建造者或增加新的具體建造者,用戶使用不同的具體建造者即可得到不同的產品對象。
可以更加精細地控制產品的創建過程。將復雜產品的創建步驟分解在不同的方法中,使得創建過程更加清晰,也更方便使用程序來控制創建過程。
增加新的具體建造者無須修改原有類庫的代碼,指揮者類針對抽象建造者類編程,系統擴展方便,符合“開閉原則”。
建造者模式的缺點如下:
建造者模式所創建的產品一般具有較多的共同點,其組成部分相似,如果產品之間的差異性很大,則不適合使用建造者模式,因此其使用范圍受到一定的限制。
如果產品的內部變化復雜,可能會導致需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大。
模式適用環境
在以下情況下可以使用建造者模式:
- 需要生成的產品對象有復雜的內部結構,這些產品對象通常包含多個成員屬性。
- 需要生成的產品對象的屬性相互依賴,需要指定其生成順序。
- 對象的創建過程獨立於創建該對象的類。在建造者模式中引入了指揮者類,將創建過程封裝在指揮者類中,而不在建造者類中。
- 隔離復雜對象的創建和使用,並使得相同的創建過程可以創建不同的產品。
四.原型模式(對象型)
定義:用原型實例指定創建對象的類型,並且通過拷貝這個原型來創建新的對象。
說明:有些對象是需要頻繁創建的,用原型實例指定創建對象的類型,並且通過拷貝這個原型來創建新的同類型的對象,分為淺克隆和深克隆,淺克隆只復制拷貝的對象,不復制引用的對象,即成員對象不復制;深克隆,引用也同樣復制。
在以下情況下可以使用原型模式:
創建新對象成本較大,新的對象可以通過原型模式對已有對象進行復制來獲得,如果是相似對象,則可以對其屬性稍作修改。
如果系統要保存對象的狀態,而對象的狀態變化很小,或者對象本身占內存不大的時候,也可以使用原型模式配合備忘錄模式來應用。相反,如果對象的狀態變化很大,或者對象占用的內存很大,那么采用狀態模式會比原型模式更好。
需要避免使用分層次的工廠類來創建分層次的對象,並且類的實例對象只有一個或很少的幾個組合狀態,通過復制原型對象得到新實例可能比使用構造函數創建一個新實例更加方便。
五.單例模式(對象型)
模式動機
a) 如何保證一個類只有一個實例並且這個實例易於被訪問呢?定義一個全局變量可以確保對象隨時都可以被訪問,但不能防止我們實例化多個對象。
b) 一個更好的解決辦法是讓類自身負責保存它的唯一實例。這個類可以保證沒有其他實例被創建,並且它可以提供一個訪問該實例的方法。這就是單例模式的模式動機。
定義:保證某一個類只有一個實例,並提供一個訪問它的全局訪問點
單例模式的要點有三個:一是某個類只能有一個實例;二是它必須自行創建這個實例;三是它必須自行向整個系統提供這個實例。單例模式是一種對象創建型模式。單例模式又名單件模式或單態模式
餓漢式單例與懶漢式單例類比較
餓漢式單例類在自己被加載時就將自己實例化。單從資源利用效率角度來講,這個比懶漢式單例類稍差些。從速度和反應時間角度來講,則比懶漢式單例類稍好些。
懶漢式單例類在實例化時,必須處理好在多個線程同時首次引用此類時的訪問限制問題,特別是當單例類作為資源控制器,在實例化時必然涉及資源初始化,而資源初始化很有可能耗費大量時間,這意味着出現多線程同時首次引用此類的機率變得較大,需要通過同步化機制進行控制。
2.結構性設計模式Structural(7種)
結構型模式所描述的是如何將類和對象結合在一起來形成一個更大的結構,它描述兩種不同的事物:類和對象,根據這一點,可分為類結構型和對象結構型模式。類結構型模式關心類的組合,由多個類可以組合成一個更大的系統,在類結構型模式中一般只存在繼承關系和實現關系;對象結構型模式關心類與對象的組合,通過關聯關系使得在一個類中定義另一個類的實例對象,然后通過該對象調用其方法。根據“合成復用原則”,在系統中盡量使用關聯關系來替代繼承關系,因此大部分結構型模式都是對象結構型模式
一. 適配器模式(對象型和類型)
模式動機
a) 在軟件開發中采用類似於電源適配器的設計和編碼技巧被稱為適配器模式。
b) 通常情況下,客戶端可以通過目標類的接口訪問它所提供的服務。有時,現有的類可以滿足客戶類的功能需要,但是它所提供的接口不一定是客戶類所期望的,這可能是因為現有類中方法名與目標類中定義的方法名不一致等原因所導致的。
c) 在這種情況下,現有的接口需要轉化為客戶類期望的接口,這樣保證了對現有類的重用。如果不進行這樣的轉化,客戶類就不能利用現有類所提供的功能,適配器模式可以完成這樣的轉化。
d) 在適配器模式中可以定義一個包裝類,包裝不兼容接口的對象,這個包裝類指的就是適配器(Adapter),它所包裝的對象就是適配者(Adaptee),即被適配的類。
e) 適配器提供客戶類需要的接口,適配器的實現就是把客戶類的請求轉化為對適配者的相應接口的調用。也就是說:當客戶類調用適配器的方法時,在適配器類的內部將調用適配者類的方法,而這個過程對客戶類是透明的,客戶類並不直接訪問適配者類。因此,適配器可以使由於接口不兼容而不能交互的類可以一起工作。這就是適配器模式的模式動機。
定義:將一個接口轉換成客戶希望的另一個接口,從而使接口不兼容的那些類可以在一起工作。
說明:適配器模式既可作為類結構模式,也可作為對象結構模式,類適配模式是通過一個具體的類,將適配者適配到目標接口當中;對象適配模式是指一個適配器可以將多個不同的適配者適配到同一目標
類適配器模式:
public class Adapter extends Adaptee implements Target
{
public void request()
{
specificRequest();
}
}
public class Adapter extends Target
{
private Adaptee adaptee;
public Adapter(Adaptee adaptee)
{
this.adaptee=adaptee;
}
public void request()
{
adaptee.specificRequest();
}
}
適配器模式包含如下角色:
ü Target:目標抽象類
ü Adapter:適配器類
ü Adaptee:適配者類
ü Client:客戶類
適配器模式的優點
ü 將目標類和適配者類解耦,通過引入一個適配器類來重用現有的適配者類,而無須修改原有代碼。
ü 增加了類的透明性和復用性,將具體的實現封裝在適配者類中,對於客戶端類來說是透明的,而且提高了適配者的復用性。
ü 靈活性和擴展性都非常好,通過使用配置文件,可以很方便地更換適配器,也可以在不修改原有代碼的基礎上增加新的適配器類,完全符合“開閉原則”。
類適配器模式還具有如下優點:
ü 由於適配器類是適配者類的子類,因此可以在適配器類中置換一些適配者的方法,使得適配器的靈活性更強。
類適配器模式的缺點如下:
ü 對於Java、C#等不支持多重繼承的語言,一次最多只能適配一個適配者類,而且目標抽象類只能為抽象類,不能為具體類,其使用有一定的局限性,不能將一個適配者類和它的子類都適配到目標接口。
在以下情況下可以使用適配器模式:
ü 系統需要使用現有的類,而這些類的接口不符合系統的需要。
ü 想要建立一個可以重復使用的類,用於與一些彼此之間沒有太大關聯的一些類,包括一些可能在將來引進的類一起工作。
一. 橋接模式(對象型模式)
將抽象部分和實現部分分離,使它們都可以獨立地發生變化,橋接模式是一種對象的結構模式,橋接模式類似於多重繼承方案,但是多重繼承方案往往違背了類的單一職責原則,並且復用性較差,橋接模式相對於多重繼承來說,是更好的解決方案,橋接模式既能達到多重繼承的用途,又能有利於復用。
模式動機
w 設想如果要繪制矩形、圓形、橢圓、正方形,我們至少需要4個形狀類,但是如果繪制的圖形需要具有不同的顏色,如紅色、綠色、藍色等,此時至少有如下兩種設計方案:
w 第一種設計方案是為每一種形狀都提供一套各種顏色的版本。
w 第二種設計方案是根據實際需要對形狀和顏色進行組合。
w 對於有兩個變化維度(即兩個變化的原因)的系統,采用方案二來進行設計系統中類的個數更少,且系統擴展更為方便。設計方案二即是橋接模式的應用。橋接模式將繼承關系轉換為關聯關系,從而降低了類與類之間的耦合,減少了代碼編寫量
定義:將抽象部分和實現部分分離,使它們都可以獨立地發生變化
橋接模式包含如下角色:
Abstraction:抽象類
RefinedAbstraction:擴充抽象類
Implementor:實現類接口
ConcreteImplementor:具體實現類
理解橋接模式,重點需要理解如何將抽象化(Abstraction)與實現化(Implementation)脫耦,使得二者可以獨立地變化。
ü 抽象化:抽象化就是忽略一些信息,把不同的實體當作同樣的實體對待。在面向對象中,將對象的共同性質抽取出來形成類的過程即為抽象化的過程。
ü 實現化:針對抽象化給出的具體實現,就是實現化,抽象化與實現化是一對互逆的概念,實現化產生的對象比抽象化更具體,是對抽象化事物的進一步具體化的產物。
ü 脫耦:脫耦就是將抽象化和實現化之間的耦合解脫開,或者說是將它們之間的強關聯改換成弱關聯,將兩個角色之間的繼承關系改為關聯關系。橋接模式中的所謂脫耦,就是指在一個軟件系統的抽象化和實現化之間使用關聯關系(組合或者聚合關系)而不是繼承關系,從而使兩者可以相對獨立地變化,這就是橋接模式的用意。
在以下情況下可以使用橋接模式:
ü 如果一個系統需要在構件的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個層次之間建立靜態的繼承聯系,通過橋接模式可以使它們在抽象層建立一個關聯關系。
ü 抽象化角色和實現化角色可以以繼承的方式獨立擴展而互不影響,在程序運行時可以動態將一個抽象化子類的對象和一個實現化子類的對象進行組合,即系統需要對抽象化角色和實現化角色進行動態耦合。
ü 一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴展。
ü 雖然在系統中使用繼承是沒有問題的,但是由於抽象化角色和具體化角色需要獨立變化,設計要求需要獨立管理這兩者。
ü 對於那些不希望使用繼承或因為多層次繼承導致系統類的個數急劇增加的系統,橋接模式尤為適用。
一. 組合模式(對象型模式),也稱為整體-部分模式
是一種整體和部分的結構,通過組合多個對象形成樹形結構,用這種方式表示整體和部分的結構層次。在組合模式中,對單個對象和組合對象的使用具有一致性。
定義:將對象組合成樹形結構以表示整體和部分的層次結構,使得用戶對單個對象和組合對象的使用具有一致性
ü 組合模式包含如下角色:
- Component: 抽象構件
- Leaf: 葉子構件
- Composite: 容器構件
- Client: 客戶類
ü 在以下情況下可以使用組合模式:
- 需要表示一個對象整體或部分層次,在具有整體和部分的層次結構中,希望通過一種方式忽略整體與部分的差異,可以一致地對待它們。
- 讓客戶能夠忽略不同對象層次的變化,客戶端可以針對抽象構件編程,無須關心對象層次結構的細節。
- 對象的結構是動態的並且復雜程度不一樣,但客戶需要一致地處理它們。
一. 裝飾模式(對象模式)
一般有兩種方式可以實現給一個類或對象增加行為:
a) 繼承機制,使用繼承機制是給現有類添加功能的一種有效途徑,通過繼承一個現有類可以使得子類在擁有自身方法的同時還擁有父類的方法。但是這種方法是靜態的,用戶不能控制增加行為的方式和時機。
b) 關聯機制,即將一個類的對象嵌入另一個對象中,由另一個對象來決定是否調用嵌入對象的行為以便擴展自己的行為,我們稱這個嵌入的對象為裝飾器(Decorator)。
它可以動態地對一個對象增加一些額外的職責,就增加對象功能來說,比生成子類更加靈活一些,為類增加職責就是定義類的功能,為達到這個目的,可以增加子類的方法來實現,但是裝飾模式也可以做到,而且更加靈活。
定義:動態地對一個對象增加額外的職責。它提供了用子類擴展功能的一個靈活的替代,比派生一個子類更加靈活。
當需要為對象動態的添加一些功能,並且可以動態的撤銷或是不能使用子類展功能的時候,這兩種情況時可以使用裝飾模式
ü 裝飾模式包含如下角色:
- Component: 抽象構件
- ConcreteComponent: 具體構件
- Decorator: 抽象裝飾類
- ConcreteDecorator: 具體裝飾類
ü 在以下情況下可以使用裝飾模式:
ü 在不影響其他對象的情況下,以動態、透明的方式給單個對象添加職責。
ü 需要動態地給一個對象增加功能,這些功能也可以動態地被撤銷。
ü 當不能采用繼承的方式對系統進行擴充或者采用繼承不利於系統擴展和維護時。不能采用繼承的情況主要有兩類:第一類是系統中存在大量獨立的擴展,為支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增長;第二類是因為類定義不能繼承(如final類)。
典型的抽象裝飾類代碼:
public class Decorator extends Component
{
private Component component;
public Decorator(Component component)
{
this.component=component;
}
public void operation()
{
component.operation();
}
}
典型的具體裝飾類代碼:
public class ConcreteDecorator extends Decorator
{
public ConcreteDecorator(Component component)
{
super(component);
}
public void operation()
{
super.operation();
addedBehavior();
}
public void addedBehavior()
{
//新增方法
}
}
一. 外觀模式(對象結構模式)
定義:定義一個高層接口,為子系統中的一組接口提供一個一致的外觀,從而簡化了該子系統的使用
ü 外觀模式包含如下角色:
ü Facade: 外觀角色
ü SubSystem:子系統角色
ü 典型的外觀角色代碼:
public class Facade
{
private SubSystemA obj1 = new SubSystemA();
private SubSystemB obj2 = new SubSystemB();
private SubSystemC obj3 = new SubSystemC();
public void method()
{
obj1.method();
obj2.method();
obj3.method();
}
}
ü 在以下情況下可以使用外觀模式:
ü 當要為一個復雜子系統提供一個簡單接口時可以使用外觀模式。該接口可以滿足大多數用戶的需求,而且用戶也可以越過外觀類直接訪問子系統。
ü 客戶程序與多個子系統之間存在很大的依賴性。引入外觀類將子系統與客戶以及其他子系統解耦,可以提高子系統的獨立性和可移植性。
ü 在層次化結構中,可以使用外觀模式定義系統中每一層的入口,層與層之間不直接產生聯系,而通過外觀類建立聯系,降低層之間的耦合度。
ü 不要試圖通過外觀類為子系統增加新行為
ü 不要通過繼承一個外觀類在子系統中加入新的行為,這種做法是錯誤的。外觀模式的用意是為子系統提供一個集中化和簡化的溝通渠道,而不是向子系統加入新的行為,新的行為的增加應該通過修改原有子系統類或增加新的子系統類來實現,不能通過外觀類來實現。
ü 外觀模式與迪米特法則
ü 外觀模式創造出一個外觀對象,將客戶端所涉及的屬於一個子系統的協作伙伴的數量減到最少,使得客戶端與子系統內部的對象的相互作用被外觀對象所取代。外觀類充當了客戶類與子系統類之間的“第三者”,降低了客戶類與子系統類之間的耦合度,外觀模式就是實現代碼重構以便達到“迪米特法則”要求的一個強有力的武器。
一. 享元模式(對象型模式)
定義:提供支持大量細粒度對象共享的有效方法
通過運用共享技術,有效地自制細粒度的對象,系統只使用少量的對象,而這些對象都很類似,狀態變化很小,對象使用次數增多。享元對象可以做到共享的關鍵,是能區分出內部狀態和外部狀態。內部狀態是存儲在享元對象的內部,並且不會隨時間和環境而發生變化,內部狀態是可以共享的。外部狀態是隨着外部環境的改變而改變的,不可以共享,所以外部狀態必須由客戶端保存,並且在享元對象被創建之后,在需要使用的時候,傳遞到享元對象的內部,外部狀態之間是相互獨立的。
一. 代理模式(對象型模式)
模式動機
a) 在某些情況下,一個客戶不想或者不能直接引用一個對象,此時可以通過一個稱之為“代理”的第三者來實現間接引用。代理對象可以在客戶端和目標對象之間起到中介的作用,並且可以通過代理對象去掉客戶不能看到的內容和服務或者添加客戶需要的額外服務。
定義:為其他對象提供一種代理,由代理對象控制這個對象的訪問
協調調用者和被調用者,減低耦合度
缺點是請求速度變慢,而且增加了額外的工作量
ü 代理模式包含如下角色:
- Subject: 抽象主題角色
- Proxy: 代理主題角色
- RealSubject: 真實主題角色
ü 根據代理模式的使用目的,常見的代理模式有以下幾種類型:
ü 遠程(Remote)代理:為一個位於不同的地址空間的對象提供一個本地的代理對象,這個不同的地址空間可以是在同一台主機中,也可是在另一台主機中,遠程代理又叫做大使(Ambassador)。
ü 虛擬(Virtual)代理:如果需要創建一個資源消耗較大的對象,先創建一個消耗相對較小的對象來表示,真實對象只在需要時才會被真正創建。
Copy-on-Write代理:它是虛擬代理的一種,把復制(克隆)操作延遲到只有在客戶端真正需要時才執行。一般來說,對象的深克隆是一個開銷較大的操作,Copy-on-Write代理可以讓這個操作延遲,只有對象被用到的時候才被克隆。