建立型模式的主要關注點是“怎樣建立對象?”,它的主要特點是“将對象的建立與使用分離”。這樣可以降低系統的耦合度,使用者不需要關注對象的建立細節,對象的建立由相關的工廠來完成。就像我們去商場購買商品時,不需要知道商品是怎麼生産出來一樣,因為它們由專門的廠商生産。
建立型模式分為以下幾種。
單例(Singleton)模式:某個類隻能生成一個執行個體,該類提供了一個全局通路點供外部擷取該執行個體,其拓展是有限多例模式。
原型(Prototype)模式:将一個對象作為原型,通過對其進行複制而克隆出多個和原型類似的新執行個體。
工廠方法(FactoryMethod)模式:定義一個用于建立産品的接口,由子類決定生産什麼産品。
抽象工廠(AbstractFactory)模式:提供一個建立産品族的接口,其每個子類可以生産一系列相關的産品。
建造者(Builder)模式:将一個複雜對象分解成多個相對簡單的部分,然後根據不同需要分别建立它們,最後建構成該複雜對象。
在有些系統中,為了節省記憶體資源、保證資料内容的一緻性,對某些類要求隻能建立一個執行個體,這就是所謂的單例模式。
單例(Singleton)模式的定義:指一個類隻有一個執行個體,且該類能自行建立這個執行個體的一種模式。例如,Windows 中隻能打開一個任務管理器,這樣可以避免因打開多個任務管理器視窗而造成記憶體資源的浪費,或出現各個視窗顯示内容的不一緻等錯誤。
在計算機系統中,還有 Windows 的資源回收筒、作業系統中的檔案系統、多線程中的線程池、顯示卡的驅動程式對象、列印機的背景處理服務、應用程式的日志對象、資料庫的連接配接池、網站的計數器、Web 應用的配置對象、應用程式中的對話框、系統中的緩存等常常被設計成單例。
單例模式有 3 個特點:
單例類隻有一個執行個體對象;
該單例對象必須由單例類自行建立;
單例類對外提供一個通路該單例的全局通路點;
單例模式是設計模式中最簡單的模式之一。通常,普通類的構造函數是公有的,外部類可以通過“new 構造函數()”來生成多個執行個體。但是,如果将類的構造函數設為私有的,外部類就無法調用該構造函數,也就無法生成多個執行個體。這時該類自身必須定義一個靜态私有執行個體,并向外提供一個靜态的公有函數用于建立或擷取該靜态私有執行個體。
下面來分析其基本結構和實作方法。
1. 單例模式的結構
單例模式的主要角色如下。
單例類:包含一個執行個體且能自行建立這個執行個體的類。
通路類:使用單例的類。
其結構如圖1所示。

圖1單例模式的結構圖
2. 單例模式的實作
Singleton 模式通常有兩種實作形式。
第 1 種:懶漢式單例
該模式的特點是類加載時沒有生成單例,隻有當第一次調用 getlnstance 方法時才去建立這個單例。
第 2 種:餓漢式單例
該模式的特點是類一旦加載就建立一個單例,保證在調用 getInstance 方法之前單例已經存在了。
前面分析了單例模式的結構與特點,以下是它通常适用的場景的特點。
在應用場景中,某類隻要求生成一個對象的時候,如一個班中的班長、每個人的身份證号等。
當對象需要被共享的場合。由于單例模式隻允許建立一個對象,共享該對象可以節省記憶體,并加快對象通路速度。如 Web 中的配置對象、資料庫的連接配接池等。
當某類需要頻繁執行個體化,而建立的對象又頻繁被銷毀的時候,如多線程的線程池、網絡連接配接池等。
單例模式可擴充為有限的多例(Multitcm)模式,這種模式可生成有限個執行個體并儲存在 ArmyList 中,客戶需要時可随機擷取,其結構圖如圖2所示。
圖2有限的多例模式的結構圖
在有些系統中,存在大量相同或相似對象的建立問題,如果用傳統的構造函數來建立對象,會比較複雜且耗時耗資源,用原型模式生成對象就很高效,就像孫悟空拔下猴毛輕輕一吹就變出很多孫悟空一樣簡單。
原型(Prototype)模式的定義如下:用一個已經建立的執行個體作為原型,通過複制該原型對象來建立一個和原型相同或相似的新對象。在這裡,原型執行個體指定了要建立的對象的種類。用這種方式建立對象非常高效,根本無須知道對象建立的細節。例如,Windows 作業系統的安裝通常較耗時,如果複制就快了很多。
由于 Java 提供了對象的 clone() 方法,是以用 Java 實作原型模式很簡單。
1. 模式的結構
原型模式包含以下主要角色。
抽象原型類:規定了具體原型對象必須實作的接口。
具體原型類:實作抽象原型類的 clone() 方法,它是可被複制的對象。
通路類:使用具體原型類中的 clone() 方法來複制新的對象。
其結構圖如圖1所示。
圖1原型模式的結構圖
2. 模式的實作
原型模式的克隆分為淺克隆和深克隆,Java 中的 Object 類提供了淺克隆的 clone() 方法,具體原型類隻要實作 Cloneable 接口就可實作對象的淺克隆,這裡的 Cloneable 接口就是抽象原型類。
原型模式通常适用于以下場景。
對象之間相同或相似,即隻是個别的幾個屬性不同的時候。
對象的建立過程比較麻煩,但複制比較簡單的時候。
原型模式可擴充為帶原型管理器的原型模式,它在原型模式的基礎上增加了一個原型管理器 PrototypeManager 類。該類用 HashMap 儲存多個複制的原型,Client 類可以通過管理器的 get(String id) 方法從中擷取複制的原型。其結構圖如圖2所示。
帶原型管理器的原型模式的結構圖
圖2帶原型管理器的原型模式的結構圖
在現實生活中社會分工越來越細,越來越專業化。各種産品有專門的工廠生産,徹底告别了自給自足的小農經濟時代,這大大縮短了産品的生産周期,提高了生産效率。同樣,在軟體開發中能否做到軟體對象的生産和使用相分離呢?能否在滿足“開閉原則”的前提下,客戶随意增删或改變對軟體相關對象的使用呢?
工廠方法(FactoryMethod)模式的定義:定義一個建立産品對象的工廠接口,将産品對象的實際建立工作推遲到具體子工廠類當中。這滿足建立型模式中所要求的“建立與使用相分離”的特點。
我們把被建立的對象稱為“産品”,把建立産品的對象稱為“工廠”。如果要建立的産品不多,隻要一個工廠類就可以完成,這種模式叫“簡單工廠模式”,它不屬于 GoF 的 23 種經典設計模式,它的缺點是增加新産品時會違背“開閉原則”。
這裡介紹的“工廠方法模式”是對簡單工廠模式的進一步抽象化,其好處是可以使系統在不修改原來代碼的情況下引進新的産品,即滿足開閉原則。
工廠方法模式的主要優點有:
使用者隻需要知道具體工廠的名稱就可得到所要的産品,無須知道産品的具體建立過程;
在系統增加新的産品時隻需要添加具體産品類和對應的具體工廠類,無須對原工廠進行任何修改,滿足開閉原則;
其缺點是:每增加一個産品就要增加一個具體産品類和一個對應的具體工廠類,這增加了系統的複雜度。
工廠方法模式由抽象工廠、具體工廠、抽象産品和具體産品等4個要素構成。這裡來分析其基本結構和實作方法。
工廠方法模式的主要角色如下。
抽象工廠(Abstract Factory):提供了建立産品的接口,調用者通過它通路具體工廠的工廠方法 newProduct() 來建立産品。
具體工廠(ConcreteFactory):主要是實作抽象工廠中的抽象方法,完成具體産品的建立。
抽象産品(Product):定義了産品的規範,描述了産品的主要特性和功能。
具體産品(ConcreteProduct):實作了抽象産品角色所定義的接口,由具體工廠來建立,它同具體工廠之間一一對應。
其結構圖如圖1所示。
圖1工廠方法模式的結構圖
工廠方法模式通常适用于以下場景。
客戶隻知道建立産品的工廠名,而不知道具體的産品名。如 TCL 電視工廠、海信電視工廠等。
建立對象的任務由多個具體子工廠中的某一個完成,而抽象工廠隻提供建立産品的接口。
客戶不關心建立産品的細節,隻關心産品的品牌。
當需要生成的産品不多且不會增加,一個具體工廠類就可以完成任務時,可删除抽象工廠類。這時工廠方法模式将退化到簡單工廠模式,其結構圖如圖2所示。
圖2簡單工廠模式的結構圖
前面介紹的工廠方法模式中考慮的是一類産品的生産,如畜牧場隻養動物、電視機廠隻生産電視機。
同種類稱為同等級,也就是說:工廠方法模式隻考慮生産同等級的産品,但是在現實生活中許多工廠是綜合型的工廠,能生産多等級(種類) 的産品,如農場裡既養動物又種植物,電器廠既生産電視機又生産洗衣機或空調。
下面要介紹的抽象工廠模式将考慮多等級産品的生産,将同一個具體工廠所生産的位于不同等級的一組産品稱為一個産品族,圖 1 所示的是海爾工廠和 TCL 工廠所生産的電視機與空調對應的關系圖。
電器工廠的産品等級與産品族
圖1 電器工廠的産品等級與産品族
抽象工廠(AbstractFactory)模式的定義:是一種為通路類提供一個建立一組相關或互相依賴對象的接口,且通路類無須指定所要産品的具體類就能得到同族的不同等級的産品的模式結構。
抽象工廠模式是工廠方法模式的更新版本,工廠方法模式隻生産一個等級的産品,而抽象工廠模式可生産多個等級的産品。
使用抽象工廠模式一般要滿足以下條件。
系統中有多個産品族,每個具體工廠建立同一族但屬于不同等級結構的産品。
系統一次隻可能消費其中某一族産品,即同族的産品一起使用。
抽象工廠模式除了具有工廠方法模式的優點外,其他主要優點如下。
可以在類的内部對産品族中相關聯的多等級産品共同管理,而不必專門引入多個新的類來進行管理。
當增加一個新的産品族時不需要修改原代碼,滿足開閉原則。
其缺點是:當産品族中需要增加一個新的産品時,所有的工廠類都需要進行修改。
抽象工廠模式同工廠方法模式一樣,也是由抽象工廠、具體工廠、抽象産品和具體産品等 4 個要素構成,但抽象工廠中方法個數不同,抽象産品的個數也不同。現在我們來分析其基本結構和實作方法。
抽象工廠模式的主要角色如下。
抽象工廠(Abstract Factory):提供了建立産品的接口,它包含多個建立産品的方法 newProduct(),可以建立多個不同等級的産品。
具體工廠(Concrete Factory):主要是實作抽象工廠中的多個抽象方法,完成具體産品的建立。
抽象産品(Product):定義了産品的規範,描述了産品的主要特性和功能,抽象工廠模式有多個抽象産品。
具體産品(ConcreteProduct):實作了抽象産品角色所定義的接口,由具體工廠來建立,它 同具體工廠之間是多對一的關系。
抽象工廠模式的結構圖如圖 2 所示。
圖2 抽象工廠模式的結構圖
從圖 2 可以看出抽象工廠模式的結構同工廠方法模式的結構相似,不同的是其産品的種類不止一個,是以建立産品的方法也不止一個。
抽象工廠模式最早的應用是用于建立屬于不同作業系統的視窗構件。如 java 的 AWT 中的 Button 和 Text 等構件在 Windows 和 UNIX 中的本地實作是不同的。
抽象工廠模式通常适用于以下場景:
當需要建立的對象是一系列互相關聯或互相依賴的産品族時,如電器工廠中的電視機、洗衣機、空調等。
系統中有多個産品族,但每次隻使用其中的某一族産品。如有人隻喜歡穿某一個品牌的衣服和鞋。
系統中提供了産品的類庫,且所有産品的接口相同,用戶端不依賴産品執行個體的建立細節和内部結構。
抽象工廠模式的擴充有一定的“開閉原則”傾斜性:
當增加一個新的産品族時隻需增加一個新的具體工廠,不需要修改原代碼,滿足開閉原則。
當産品族中需要增加一個新種類的産品時,則所有的工廠類都需要進行修改,不滿足開閉原則。
另一方面,當系統中隻存在一個等級結構的産品時,抽象工廠模式将退化到工廠方法模式。
在軟體開發過程中有時需要建立一個複雜的對象,這個複雜對象通常由多個子部件按一定的步驟組合而成。例如,計算機是由 OPU、主機闆、記憶體、硬碟、顯示卡、機箱、顯示器、鍵盤、滑鼠等部件組裝而成的,采購員不可能自己去組裝計算機,而是将計算機的配置要求告訴計算機銷售公司,計算機銷售公司安排技術人員去組裝計算機,然後再交給要買計算機的采購員。
生活中這樣的例子很多,如遊戲中的不同角色,其性别、個性、能力、臉型、體型、服裝、發型等特性都有所差異;還有汽車中的方向盤、發動機、車架、輪胎等部件也多種多樣;每封電子郵件的發件人、收件人、主題、内容、附件等内容也各不相同。
以上所有這些産品都是由多個部件構成的,各個部件可以靈活選擇,但其建立步驟都大同小異。這類産品的建立無法用前面介紹的工廠模式描述,隻有建造者模式可以很好地描述該類産品的建立。
建造者(Builder)模式的定義:指将一個複雜對象的構造與它的表示分離,使同樣的建構過程可以建立不同的表示,這樣的設計模式被稱為建造者模式。它是将一個複雜的對象分解為多個簡單的對象,然後一步一步建構而成。它将變與不變相分離,即産品的組成部分是不變的,但每一部分是可以靈活選擇的。
該模式的主要優點如下:
各個具體的建造者互相獨立,有利于系統的擴充。
用戶端不必知道産品内部組成的細節,便于控制細節風險。
其缺點如下:
産品的組成部分必須相同,這限制了其使用範圍。
如果産品的内部變化複雜,該模式會增加很多的建造者類。
建造者(Builder)模式和工廠模式的關注點不同:建造者模式注重零部件的組裝過程,而工廠方法模式更注重零部件的建立過程,但兩者可以結合使用。
建造者(Builder)模式由産品、抽象建造者、具體建造者、指揮者等 4 個要素構成,現在我們來分析其基本結構和實作方法。
建造者(Builder)模式的主要角色如下。
産品角色(Product):它是包含多個組成部件的複雜對象,由具體建造者來建立其各個滅部件。
抽象建造者(Builder):它是一個包含建立産品各個子部件的抽象方法的接口,通常還包含一個傳回複雜産品的方法 getResult()。
具體建造者(Concrete Builder):實作 Builder 接口,完成複雜産品的各個部件的具體建立方法。
指揮者(Director):它調用建造者對象中的部件構造與裝配方法完成複雜對象的建立,在指揮者中不涉及具體産品的資訊。
其結構圖如圖 1 所示。
建造者模式的結構圖
圖1 建造者模式的結構圖
建造者(Builder)模式建立的是複雜對象,其産品的各個部分經常面臨着劇烈的變化,但将它們組合在一起的算法卻相對穩定,是以它通常在以下場合使用。
建立的對象較複雜,由多個部件構成,各部件面臨着複雜的變化,但構件間的建造順序是穩定的。
建立複雜對象的算法獨立于該對象的組成部分以及它們的裝配方式,即産品的建構過程和最終的表示是獨立的。
建造者(Builder)模式在應用過程中可以根據需要改變,如果建立的産品種類隻有一種,隻需要一個具體建造者,這時可以省略掉抽象建造者,甚至可以省略掉指揮者角色。
歸檔:我的知識棧:目錄(更新中...)
作者:菜鳥-傳奇
<b> </b>