close

以角色生成為例,對於各種類的角色生成,一般做法是在生成系統類別實作各種角色生成的方法,但是這種作法重複性高。此外,將產生相同類別的實作,分散在不同的遊戲功能之下,也比較不容易管理

可以用「工廠方法模式」解決

定義:定義一個可以產生物件的介面,但是讓子物件決定產生哪一個類別的物件。工廠方法模式讓類別實例化程序延遲到子類別中實行
 

工廠方法模式就是將類別「產生物件的流程」集合管理的模式。集合管理的好處:

  1. 能針對物件產生的流程制定規則
  2. 減少客戶端參與物件生成的過程,尤其是對那種類別物件生產過程過於複雜的,如果讓客戶端操作物件的組裝過程,將使得客戶端與該類別的耦合度過高,不利於後續的專案維護

 

以汽車生產工廠為例,有一家汽車公司,生產各式各樣的車,像房車、小貨車、大卡車都是他們的產品,而每一個大類別下又有不同功能及品牌

所以,生產部門可以先定義一個「生產車」的介面,從這個介面可以取得生產部門所產的車,而之後這個介面會衍生3個子類別,每個子類別負責這家公司的一種車款,分別是房車工廠、小貨車工廠、大卡車工廠

當業務部門接到50台房車的訂單後,只要取得房車工廠的物件,之後就能對房車工廠下達生產的命令

最後,業務部門就能取得50台房車,至於這50台房車是怎麼在生產線組裝的,業務部門完全不用知道

 

工廠方法模式的UML:

Product(產品類別)

定義產品類別的操作介面,而這個產品將由工廠產出

ConcreteProduct(產品實作)

實作產品功能的類別,可以不只定義一個產品實作類別,這些實作類別的物件都會由ConcreteCreator(工廠實作類別)產生

Creator(工廠介面)

定義能產生Product(產品類別)的方法:FactoryMethod

ConcreteCreator(工廠實作類別)

實作FactoryMethod,並產生指定的ConcreteProduct(產品實作)

 

而在工廠方法模式的實作上,以C#為例有4種實作方式(C#支援泛型)

  1. 由子類別產生


    測試:
  2. 在FactoryMethod增加參數
    由不同子類別工廠產生不同產品類別物件,在遇到產品類別物件非常多種的時候,容易造成「工廠子類別暴增」的情況,如果有上述情況時,可以改由單一個FactoryMethod方法,配合傳入參數的方式,來決定要產生的產品類別

    測試:

    這種做法是比較常用的實作方法,但對於switch/case語法帶來的缺點就必須要加以衡量,有沒有不必用那麼多工廠子類別去實作,又不用switch case來條例所有類別的方式?
    沒錯,C#支援泛型,那剛好符合這項要求
  3. Creator泛型類別
    跟第一種方式比較起來,可省去繼承,改用「T類別型別」方式

    測試:
  4. FactoryMethod泛型方法
    泛型類別不使用繼承的方式實作,所以客戶端無法取得「工廠介面」,所以當要取得「工廠類別」時,可以改用泛型方法來實作工廠方法模式

    測試:

    使用泛型方法實作,除了擁有「工廠介面」外,也免去了switch case語法帶來的缺點

四種實作選擇,一般會按實務情況,分析工廠類別與其他遊戲系、客戶端的互動情況決定

 

當類別的物件產生時,若出現下列情況

  • 需要複雜的流程
  • 需要載入外部資源,例如:網路、儲存設備、資料庫
  • 有物件上限
  • 可重複使用

就建議使用工廠方法模式來實作一個工廠類別

前面有用泛型實作工廠方法,但呼叫泛型方法的系統,必須知道可以傳入泛型方法的T類別,知道越多T類別,對於系統的獨立性就越不利,雖然switch case有擴充、修改上的缺點,但可以降低耦合

這樣就可以拿工廠方法模是去實作角色工廠

這邊舉例帶一下:

會有一個角色工廠的抽象介面,提供兩個工廠方法來產生我方與敵方的陣營角色

再來就是角色工廠的實作,實際產出物件的地方

我方角色的介面,我方角色介面衍生的各種角色...就是產品

敵方角色的介面,敵方角色介面衍生的各種角色...就是另一項產品

 

工廠的運用:

  • 角色工廠:產生對應的角色,設定模型、加入武器,取得角色數值,加入AI,加入角色管理系統
  • 資源載入工廠:負責將放置在檔案目錄下的Unity3D資源Asset實體化的工廠,這些資源包括:3D模型、2D模型、音效音樂...等。因為Unity3D在Asset載入時,有些策略及步驟是具有選擇性的或可進行最佳化的,並且也能減少客戶端直接取得Unity3D資源的耦合
  • 武器工廠:負責建立角色單位使用的武器,因為產生的過程也需要多個步驟才完成,所以集中一個工廠下實作
  • 數值產生工廠:角色必須使用數值來代表能力(生命力、移動速度)。這些數值組合在遊戲設計的過程中,是需要被量化及事先計算的,所以數值往往以一組一組的方式被記錄及初始化,並且以指定編號的方式,將特定數值指定給角色

 

當面對變動時:

假設針對某工廠方法要新增一個參數時,必須同時修改所有客戶端,但隊於修改的程度及影響的範圍而言,仍較容易預估,可以利用編程工具「找尋被參照」功能,就可以找到所有使用方法的地方。另外,想更改產生流程及功能組裝的規則時,只需要更動工廠方法內的實作程式碼,將修改侷限在一個地方

而當工廠以「介面」形式存在時,代表有機會更換不同的「工廠實作類別」來達成不同設計需求

以資源載入工廠為例:負責Unity資源的載入,可從不同地方做載入

  • 專案的Resource目錄下
  • 使用目錄符號C:\xxx\xxx取得,本機或區網中的電腦目錄
  • 使用UnityEngine.WWW類別取得放在網頁伺服器上的AssetBundle資源

 

與其他模式合作:

  • 角色工廠中,產生不同陣營的角色時,會搭配建造者模式(Builder)的需求,將需要的參數設定給角色建造者
  • 本地資源載入工廠若同時要求系統效能的最佳化,可以使用代理者模式(Proxy)來載入效能最佳化
  • 數值產生工廠可使用享元模式(Flyweight)來減少重複物件產生

 

參考《設計模式與遊戲開發的完美結合》的DesignPattern-FactoryMethod工廠方法模式

創作者介紹
創作者 Kouhei 的頭像
Kouhei

遊戲開發之路

Kouhei 發表在 痞客邦 留言(0) 人氣()