《設計模式》之Creational模式:簡介

Creational Patterns簡介

創造(Creational)設計模式抽象了實例化的過程。它使得系統可以獨立於對象的創建、組成和表示。一個類的Creational模式利用繼承機制來改變它實例化的類。

當一個系統發展到更依賴於對象組合而不是類的繼承時,Creational模式變得尤其重要。在這種情況下,不能將一些程序功能寫死,而是定義一個小一點的基本功能集合,然後由其去構成其它複雜的功能。因此,創建特定功能的對象不僅僅是簡單地實例化一個類。

在這裏需要強調兩點:第一,Creational模式都封裝了該系統所需的具體類的內容;第二,這種模式隱藏了這些具體類如何創建和如何被放在一起的。在什麼被創建、由誰創建、如何創建和何時創建,這幾個方面Creational模式給予你了很大的靈活性。這種模式可以讓你的系統配置結構和功能上廣泛變化的“產品(product)”對象。這種配置可以是靜態的(在編譯時指定),或者是動態的(運行時)。

一些Creational模式是競爭關係。例如,有些案例中,Prototype和Abstract Factory模式都可以發揮很好的作用。有些時候,它們又相互補充:Builder模式可以使用一種其它的模式來構建組件。Prototype在實現的時候可以用Singleton。

因爲這些Creational模式是緊密關聯的,我們將要學習5種這種模式,來對比它們之間異同。我們將會使用一個實際案例–建立一個迷宮遊戲–來展現具體的實現。這個迷宮遊戲的具體設計在講述不同的模式時可能會有些變化。有時,這個遊戲就是尋找一條出去的路,所以玩家將會智能看到迷宮的局部。有時,迷宮又會有各種難題和危險,迷宮將會展現出已經探索過的區域。

我們將會忽略迷宮的很多細節,也不必關係是單個玩家或者多個玩家。我們只關心迷宮如何構建的。我們將迷宮第一成一個房間的集合。一個房間會知道它的鄰居,它的鄰居可能是其它房間、一堵牆或者一個通向其它房間的門。

Room、Door和Wall類定義得了迷宮(maze)的主要組件。我們在這裏只定義了主要部分,我們忽略了玩家,操作和移動等其它和構建迷宮無關的功能。

下圖展示了這些類之間的關係:

這些類之間的關係

每個房間有四個邊。我們使用了C++中的枚舉方向Direction來指定房間的東西南北邊:

enum Direction{North,Sourth,East,West};

在Smalltalk中的實現使用了對應的符號來表示方向。

MapSit是迷宮所有組件的抽象類。爲了簡化例子,MapSit定義了一個操作Enter,意思是說明你如何進入的。如果你進入一個房間,那麼你的位置就會發生改變。

這裏寫圖片描述

Enter提供爲其它遊戲操作提供了一個簡單的基礎。

RoomMapSite的具體的一個類,定義了迷宮中組件的重要關係。它擁有指向其它MapSite對象的引用,同時存儲了房間號。這個號碼在迷宮中唯一標識這個房間。

這裏寫圖片描述

下面的類標識牆或者門:

這裏寫圖片描述

我們不僅需要表示迷宮的一部分,我們還需要表示迷宮整體。Maze可以使用RoomNo和房間號找到指定的房間。

這裏寫圖片描述

RoomNo可以使用線性搜索來查詢,或者hash表,或者一個簡單的數組。我們在這裏先忽略這些具體細節,我們只關係如何指定maze對象的組件。

我們定義了另一個類MazeGame,用來創建迷宮。一個直接的方法是通過一些列操作在迷宮中來添加組件,同時將它們連接起來。例如,下面的成員函數將會創建兩個房間和一個它們之間的門:

這裏寫圖片描述

這個函數很複雜,因爲它只是建立了兩個房間,顯然還有其它更簡單的方法。例如,Room的constructor可以提前初始化牆的邊,但這只是將代碼轉移到其它地方去了。這個函數最致命的問題不是它的代碼行數,而是它的靈活性,它寫死了迷宮的佈局。修改佈局需要重新寫這個函數,或者重寫(overriding)這個函數–也就是重新實現–或者修改一部分–這樣做會易出錯的,同時不利於重用。

Creational模式告訴我們如何將這設計的更加靈活,不僅僅於更少的代碼。特別的是,這樣做可以使得改變迷宮組件的類很容易。

假設在一個新的魔法迷宮遊戲中,你想重用現有的迷宮佈局代碼。這個魔法迷宮使用了新的組件,例如DoorNeedingSpell,一個可以利用咒語來鎖上和打開的門;還有EnchantedRoom,一個可能有神奇物品的房間,像魔法鑰匙和咒語。如何簡單的改變CreateMaze,讓它可以創建這個新的迷宮呢?

  1. 如果Createmaze調用虛函數而不是具體的room、wall和door的構建函數,你使用MazeGame的子類和重新定義的虛函數來改變實例化的類。這是一個Factory Method模式的例子。

  2. 如果Createmaze被傳入一個對象來創建room、wall和door。你可以通過傳入不同的參數來修改這些組件的類。這是一個Abstract Factory模式的例子。

  3. 如果Createmaze被傳入一個對象,這個對象可以在內部創建一個新的迷宮,同時可以向這個迷宮添加room、door和wall。你可以使用繼承來修改這個迷宮和這個迷宮建立的方式。這是一個Builder模式的例子。

  4. 如果Createmaze以各種原型room、door和wall對象參數化,然後它將這些組件複製添加進這個maze。你可以通過替換這些原型對象來改變maze。這是一個Prototype的例子。

最後剩下的一個Creational模式是Singleton,可以保證每個遊戲只有唯一的迷宮,同時所有遊戲對象可以訪問這個迷宮,而不需要求助於全局變量和函數。Singleton 方便的擴展和替換maze,而不需修改現有的代碼。

(本系列文章是對《Design Patterns: Elements of Reusable Object-Oriented Software》的部分翻譯和個人理解,如有錯誤,歡迎批評指正)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章