奇幻RPG(人物構建 與 Abstract Factory模式)
奇幻RPG(人物構造 與 Abstract Factory模式)
引言
在前一節,我們介紹了Strategy模式,並使用此模式實現了一個根據角色的職業來分配技能的範例(實際也就是動態地為類分配方法)。作為一款奇幻RPG,有了職業,我們還應當可以為角色選擇種族,比如說:人類(Human)、精靈(Elf)、矮人(Dwarf)、獸人(Orc)等等。而這四個種族又有著截然不同的外形,精靈皮膚灰白、有著長長的耳朵、沒有體毛和鬍鬚;矮人的皮膚與人類近似,但是身材矮小、通常留著濃密的鬍子;獸人則有著綠色的皮膚和高大的身軀,並且面目醜陋。本文將討論如何使用GOF的Abstract Factory抽象工廠來實現這樣的角色外形設計。
面向實現的方式
簡單起見,我們假設角色身體由三部分構成,分別是:頭(Head)、身材(Stature)、皮膚(Skin)。那麼對於人類的構造,我們的第一反應自然而然地想到:它應當由 HumanHead、HumanStature、HumanSkin三個類複合而成。對於精靈也是類似的設計,於是,我們實現了下面這樣的設計(本文將僅以人類和精靈為例介紹):
抽象組成身體的實體類
我們發現這樣做,每個角色與他的身體部件是牢牢繫結在一起的,每建立一個角色,我們都需要為它先行建立所有其複合的類(組成身體的實體類(Concret Class),比如HumanHead)。按照物件導向的思想,我們想到應該對這一過程進行封裝,將建立角色部件這件事委派給其他的類來完成。觀察上圖,我們發現儘管角色不同,但它們都是由三個部分構成,所以,我們所能想到的實現這一過程的第一步,就是對組成身體的實體類進行抽象,我們定義三個介面:Head、Stature、Skin,代表身體的三個部分,並且讓Human和Elf的實體類去實現這個介面:
觀察上圖,我們發現儘管定義了介面,但是如果角色Human和Elf仍然與介面的實體類關聯,那麼效果與面向實現完全相同。現在,是時候對設計做些改動,我們讓Human和Elf與介面關聯,而不是與介面的實現關聯(OO思想:面向介面程式設計,而不是面向實現程式設計)。這一次,我們的設計變成下圖:
一眼望去,我們發現的第一個問題就是:Human與Elf驚人地相似,再仔細看看,我們注意到它們除了名字不同其餘的完全一樣。我們不禁思考:有必要把兩個完全一樣的類起兩個名字分別儲存麼?答案是沒有必要,我們將它們合併成一個類,起名叫Race,設計再次變成下面這樣:
建立工廠類
看到這裡,我們可能會想:現在結構似乎已經很完善了,我們定義了介面來解決問題,也沒有為不同的角色建立多個不同的類,而只要在Race的建構函式中為代表身體部件的變數賦不同的值,就可以建立不同種族的角色。好的,那麼我們來看看如果要建立一個Human 程式碼需要如何編寫:
Head head = new HumanHead();
Stature stature = new HumanStature();
Skin skin = new HumanSkin();
Race human = new Race(head, stature, skin);
而Race的建構函式是這樣的:
public Race(head, stature, skin){
this.head = head;
this.stature = stature;
this.skin = skin;
}
我們看到,僅僅建立一個類這樣似乎太麻煩了,而且身體的部分類是角色的組成部分,為什麼它們要先於角色建立呢?
這時候,我們想到如果有一個類可以專門負責建立身體部件這件事,當我們想要建立角色的時候,將這個類傳遞給Race的建構函式就可以了。我們管建立Human身體組成部分的類稱作:HumanPartsFactory,建立Elf身體部分的類稱作ElfPartsFacotry。那麼它們應該是這樣的:
現在,我們再要建立一個Human,程式碼變成了這樣:
HumanPartsFactory humanFactory = new HumanPartsFactory();
Race Human = new Race(humanFactory);
相應的,我們的建構函式也需要改一改:
public Race(HumanPartsFactory humanFacotry){
head = humanFactory.CreateHead();
stature = humanFactory.CreateStature();
skin = humanFactory.CreateSkin();
}
一切似乎都很好,直到我們需要建立一個Elf的時候... 我們發現Race的建構函式只能接受一個HumanPartsFactory型別的引數,為了傳遞ElfPartsFactory,我們將不得不再新增一個接受ElfPartsFactory型別的建構函式。這樣顯然不好,這一次,有了之前的經驗,我們知道我們可以透過同樣的方法來解決。
看到這裡,你是否能夠體會到一些“面向介面”程式設計的意味?注意到RacePartsFactory,它內部的方法返回的都是介面型別,而其實體子類的方法返回的都是介面的實體類。如果我們之前不宣告那看似無用的介面,這裡是無法實現的。
現在,我們再次修改Race的建構函式:
public Race(RacePartsFactory raceFacotry){
head = raceFacotry.CreateHead();
stature = raceFacotry.CreateStature();
skin = raceFacotry.CreateSkin();
}
當我們需要一個Human的時候:
RacePartsFactory humanFactory = new HumanPartsFactory();
Race human = new Race(humanFactory);
當我們需要一個Elf的時候:
RacePartsFactory elfFactory = new ElfPartsFactory();
Race elf = new Race(elfFactory);
Abstract Factory設計模式
上面做的這些,使我們又完成了一個設計模式:Abstract Factory。它的正式定義是這樣的:提供一個介面用於建立一系列相互關聯或者相互依賴的物件,而不需要指定它們的實體類。
下面是本例中 Abstract Factory模式的最終圖:
程式碼實現和測試
using System;
using System.Collections.Generic;
using System.Text;
namespace AbstractFactory {
// 定義構成身體部分的介面
public interface IHead { string name { get;} }
public interface IStature { string name { get;} }
public interface ISkin { string name { get;} }
// 組成 Human 的類
public class HumanHead : IHead { public string name { get { return "Human Head"; } } }
public class HumanStature : IStature { public string name { get { return "Human Stature"; } } }
public class HumanSkin : ISkin { public string name { get { return "Human Skin"; } } }
// 組成 Elf 的類
public class ElfHead : IHead { public string name { get { return "Elf Head"; } } }
public class ElfStature : IStature { public string name { get { return "Elf Stature"; } } }
public class ElfSkin : ISkin { public string name { get { return "Elf Skin"; } } }
// 定義工廠介面
public interface IRacePartsFactory {
IHead CreateHead();
ISkin CreateSkin();
IStature CreateStature();
}
// 定義Human身體的工廠類
public class HumanPartsFactory : IRacePartsFactory {
public IHead CreateHead() {
return new HumanHead();
}
public IStature CreateStature() {
return new HumanStature();
}
public ISkin CreateSkin() {
return new HumanSkin();
}
}
// 定義Elf身體的工廠類
public class ElfPartsFactory : IRacePartsFactory {
public IHead CreateHead() {
return new ElfHead();
}
public IStature CreateStature() {
return new ElfStature();
}
public ISkin CreateSkin() {
return new ElfSkin();
}
}
// 定義 Race 類
public class Race {
public IHead Head; // 做示範用,所以沒有構建屬性
public IStature Stature;
public ISkin Skin;
public Race(IRacePartsFactory raceFactory) {
Head = raceFactory.CreateHead();
Stature = raceFactory.CreateStature();
Skin = raceFactory.CreateSkin();
}
}
class Program {
static void Main(string[] args) {
// 建立一個 精靈(Elf)
Race Elf = new Race(new ElfPartsFactory());
Console.WriteLine(Elf.Head.name);
Console.WriteLine(Elf.Stature.name);
Console.WriteLine(Elf.Skin.name);
}
}
}
總結
本文中我們一步步學習了Abstract Factory抽象工廠模式的實現。
我首先介紹了我們奇幻RPG所面臨的一個問題:我們需要建立形態各異的角色。隨後,我們透過面向實現的方式來完成了這一過程,並討論了它的不足。隨後,我們先透過介面的使用對種族進行了抽象。接著,我們由將建立角色組成部分類的過程進行了封裝,將這一過程委派給了工廠類。最後,我們又對工廠類進行了抽象,最終實現了Abstract Factory工廠模式。
希望本文能給你帶來幫助。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2768/viewspace-2811728/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 設計模式--抽象工廠模式(Abstract Factory Pattern)設計模式抽象
- 設計模式-抽象工廠模式(Abstract Factory Pattern)設計模式抽象
- Abstract Factory(抽象工廠)——物件建立型模式抽象物件模式
- 設計模式實戰 - 抽象工廠模式(Abstract Factory Pattern)設計模式抽象
- 設計模式實戰 – 抽象工廠模式(Abstract Factory Pattern)設計模式抽象
- 【圖解設計模式系列】The Abstract Factory Pattern: 抽象工廠模式圖解設計模式抽象
- Pipeline模式與Factory+Provider模式的應用模式IDE
- 《設計模式》 - 2. 工廠模式( Factory )設計模式
- 三消RPG真的香!踏上《妙連千軍》的奇幻冒險
- 設計模式--工廠方法模式(Factory Method Pattern)設計模式
- MongoDB – 使用模式構建之多型模式MongoDB模式多型
- 簡單工廠模式( Simple Factory Pattern )模式
- 構建者模式(Builder pattern)模式UI
- 設計模式(五)Builder構建者模式設計模式UI
- MongoDB – 使用模式構建之屬性模式MongoDB模式
- 設計模式系列之工廠模式三兄弟(Factory Pattern)設計模式
- PHP設計模式(一)簡單工廠模式 (Simple Factory For PHP)PHP設計模式
- OCI 與容器映象構建
- Java 8中實現構建器模式Java模式
- Gradle 與 AGP 構建 API: 配置您的構建檔案GradleAPI
- 簡單工廠模式(simple factory)及程式碼實現模式
- Selenium4+Python3系列(十一) - Page Factory設計模式Python設計模式
- 建構函式與解構函式函式
- 使用C# (.NET Core) 實現簡單工廠(Simple Factory) 和工廠方法設計模式 (Factory Method Pattern)C#設計模式
- JS 建構函式與類JS函式
- Qt構建與解析Json示例QTJSON
- 這支小團隊用500萬歐元打造出了一款優秀的奇幻RPG
- 時隔20年重映的《指環王》電影原著,如何影響了無數奇幻RPG?
- 人物丨黃維院士:構建顛覆性技術創新體系意義重大
- SAP Kyma(Extension Factory on SAP Cloud Platform)的架構簡介CloudPlatform架構
- 關積珍:智慧交通構建全新出行模式模式
- RabbitMQ 中的分散式,普通 cluster 模式的構建MQ分散式模式
- 簡單明瞭的體會構建者模式模式
- 剛剛,GPT-4o關鍵人物離職創業!曾在OpenAI最早提出構建「Her」GPT創業OpenAI
- 客戶成功是一種思維模式 | ONES 人物模式
- 牧羊少年奇幻之旅
- 使用C# (.NET Core) 實現抽象工廠設計模式 (Abstract Pattern)C#抽象設計模式
- 構建微服務的三種重要模式 - DZone微服務微服務模式