設計模式II

月亮熊發表於2024-06-24

建造者模式

在建造者模式中,通常會定義以下介面/抽象類:

抽象建造者介面(Builder):定義了構建產品各個部分的抽象方法,通常包括建立產品和設定產品各個部分的方法。具體建造者類將實現這個介面來構建產品的各個部分。
產品介面(Product):定義了產品的抽象介面,通常包括產品的屬性和行為。具體的產品類將實現這個介面來表示實際構建完成的產品。

在建造者模式中,通常涉及以下幾種具體類:

具體建造者(Concrete Builder):實現了抽象建造者介面,負責實際構建產品的各個部分。具體建造者類通常包括一個產品例項以及實現構建產品各個部分的方法。

指導者(Director):負責指導構建過程,即按照一定的順序呼叫具體建造者的方法來構建產品。

客戶端不需要直接與具體建造者類互動,而是透過指導者類根據需要自定義構建過程。這樣客戶端只需與指導者類進行互動,而不必瞭解具體的構建細節。
指導者類通常包含一個構建方法,該方法接受一個具體建造者物件作為引數,然後按照一定的順序呼叫具體建造者的方法來構建產品。指導者類根據具體的構建需求和流程,來決定呼叫具體建造者的方法的順序和方式。(通常並不直接建立產品。)

建造者模式中的指導者類並不構建一個具體的產品物件,而是協調建造者來構建複雜物件。

產品實現類(Concrete Product):具體產品類,實現了產品介面,表示最終構建完成的產品。產品實現類通常由具體建造者來建立並返回給客戶端

在建造者模式中,產品的組裝通常由客戶端程式碼負責。:客戶端透過建立指導者(Director)物件,並將具體建造者(Concrete Builder)物件傳遞給指導者,來控制產品的構建過程。然後,指導者類按照一定的順序呼叫具體建造者的方法來構建產品的各個部分。最後,客戶端透過呼叫具體建造者的方法獲取構建完成的產品物件。

原型模式
原型模式屬於建立型設計模式。透過複製現有的例項來建立新的例項
抽象原型類(Prototype):定義了一個抽象的克隆方法。
具體原型類(ConcretePrototyoe):實現抽象原型類(介面)定義的克隆方法,提供一個具體的克隆方法來複制自己。
客戶端(Client):使用原型類的物件來實現具體的操作,即透過複製原型物件來建立新的物件。
淺複製
淺複製(shallow copy)和賦值(assignment)建立物件副本的方式有著重要的區別:

物件複製的方式:

淺複製:淺複製建立一個新物件,但是對於該物件內部的元素,僅僅是複製了引用而不是複製元素本身。換句話說,淺複製建立了一個新的容器物件,但是該容器內的元素與原始物件中的元素指向相同的記憶體地址。此外的內容則是獨立的副本
賦值:賦值操作僅僅是將一個物件的引用(記憶體地址)賦給另一個變數,兩者指向同一塊記憶體區域。因此,修改其中一個變數的內容會影響到另一個變數。
影響範圍:

淺複製:對於可變物件(如列表、字典等),淺複製會建立一個新物件,但是其內部的可變元素(如列表中的元素)仍然會被共享。這意味著對於這些可變元素的修改會影響到原始物件和副本物件。
賦值:賦值操作會使兩個變數指向同一塊記憶體區域,因此對任何一個變數進行修改都會影響到另一個變數。
適用場景:

淺複製:適用於需要複製物件但又不希望複製其內部元素的場景,或者在需要修改副本物件而不影響原始物件的情況下使用。
賦值:適用於簡單的物件賦值操作,或者在需要兩個變數共享相同物件的情況下使用。
淺複製是使用預設的clone()方法來實現

在Java中,原型模式的核心是透過實現 Cloneable 介面來實現物件的克隆。這個介面沒有定義任何方法,但是它表明了該物件是可複製的
sheep = (Sheep) super.clone();
new:每次使用 "new" 關鍵字建立物件時,都會得到一個全新的物件例項,它與之前建立的物件完全獨立。
clone:使用 "clone" 方法建立的物件是原始物件的副本,但是它們之間並不是完全獨立的。通常情況下,副本物件和原始物件之間共享相同的內部狀態,但是它們在記憶體中擁有不同的引用地址
new:通常用於建立全新的物件例項,無需共享狀態或複製原始物件的情況。
clone:適用於需要建立物件副本的情況,但又希望保留物件內部狀態的情況。例如,在需要使用原始物件的副本進行修改而不影響原始物件的情況下,可以使用 "clone" 方法。

單例模式
單例模式是指在記憶體中只會建立且僅建立一次物件的設計模式。在程式中多次使用同一個物件且作用相同時,為了防止頻繁地建立物件使得記憶體飆升,單例模式可以讓程式僅在記憶體中建立一個物件,讓所有需要呼叫的地方都共享這一單例物件

有兩種型別:

懶漢式:在真正需要使用物件時才去建立該單例類物件
餓漢式:在類載入時已經建立好該單例物件,等待被程式使用

因為需要兩次判空,且對類物件加鎖,該懶漢式寫法也被稱為:Double Check(雙重校驗) + Lock(加鎖)
使用volatile防止指令重排
建立一個物件,在JVM中會經過三步:

(1)為singleton分配記憶體空間

(2)初始化singleton物件

(3)將singleton指向分配好的記憶體空間

指令重排序是指:JVM在保證最終結果正確的情況下,可以不按照程式編碼的順序執行語句,儘可能提高程式的效能

在這三步中,第2、3步有可能會發生指令重排現象,建立物件的順序變為1-3-2,會導致多個執行緒獲取物件時,有可能執行緒A建立物件的過程中,執行了1、3步驟,執行緒B判斷singleton已經不為空,獲取到未初始化的singleton物件,就會報NPE異常
使用volatile關鍵字可以防止指令重排序

1.如果一個類不能透過NEW建立例項物件(從外部呼叫建構函式),要定義為私有型別建構函式
2.私有靜態成員變數儲存唯一例項
3.向外部提供一個訪問介面去訪問例項,公有的靜態共享方法。定義為static

相關文章