閱讀本篇文章前,仔細想想看
大致上理解策略模式以及應用類別與介面進行實踐。
另外本篇會延續上一篇的範例,因此沒有看過可以先翻看前一篇的文章喔!
廢話不多說,正文開始吧!
前一篇大致上利用 RPG 角色的範例,示範了如何簡單對各種不同的角色職業 Character
,利用策略模式進行攻擊能力的策略選擇。
以上就是利用策略模式狀態下,父類別 Character
藉由一個參考點(也就是父類別的成員變數 attackRef
)連結到 Attack
介面。藉由 Attack
介面可以實踐出各種不同的攻擊策略,在這裡的範例是分別實踐出 MeleeAttack
以及 MagicAttack
。
子類別經由父類別進行繼承後 —— 由於父類別有宣告與 Attack
介面連結的參考點,子類別可以選擇其中一種 Attack
介面宣告出的策略,進行選擇攻擊的演算法,不需另外再寫一個 attack
成員方法去覆蓋父類別的 attack
方法呢。
本篇的範例程式碼可以參考這個連結。
由上一篇可以切換演算法部分進行延伸。
假若角色可能會出現不同的攻擊方式,譬如:Swordsman
除了會 MeleeAttack
(直接攻擊)外,可能還會有 StabAttack
(刺擊)這種攻擊法。
首先可以藉由 Attack
介面另訂一個新攻擊策略。
這裡就出現一個問題了:Swordsman
預設的攻擊模式(也就是它的策略)是 MeleeAttack
—— 不過還記得筆者在前一篇文章有貼過描述策略模式的一句話嗎?
Changing algorithm during runtime.
根據上面那句話的意思:如何在 runtime 期間進行切換策略(演算法)的動作呢?
換句話說,筆者不希望在建構 Swordsman
角色的時候更動它原本的設定 —— 也就是 MeleeAttack
,但是要如何在程式碼跑的過程進行更換攻擊策略的動作。
其實非常簡單,可以在父類別宣告一個 switchAttackStrategy
成員方法 —— 負責進行策略的切換;這裡的範例指的是進行攻擊方式的切換。以下是簡單的實踐:
筆者寫一段簡單的程式碼進行測試。(如圖一)
圖一:我們可以更換角色的攻擊策略囉!
如果沒有應用策略模式,想要更換策略的話,可能得設定一個 Flag 負責記錄該角色目前的攻擊方式,然後再進行 if...else...
這一類的判斷,又會回到原來那一大串判斷敘述地獄了。
然而,經由策略模式,我們可以捨棄掉多重判斷敘述的同時,也可以達到類別與介面被重複使用的功能 —— 以 Warlock
為例,它也繼承了父類別 Character
,代表 Warlock
類型的角色也可以切換不同的策略呢!
本篇唯一重點. 策略模式的優勢
策略模式最大的威力在於:新增各種策略在子類別時,不需要覆蓋父類別的實踐,就可以間接切換策略達到目的。
此外,新增的策略也可以被重複加以利用而不會影響到子類別的功能實踐。
這個優勢符合了這句話的形容 —— “Changing algorithm during runtime.”
我們緊接著使用策略模式的優勢,設計出更多 RPG 角色可能會有的功能。以下為了更熟悉策略模式的概念,筆者會繼續帶領讀者一遍又一遍地熟悉這個設計模式的實踐流程。
常理的 RPG 遊戲設計時,通常角色的攻擊方式是會根據武器特性而決定的,除非你是使出技能之類的機制才會轉換攻擊演算法。
以下來試試看能不能實踐出這個功能:設計武器 Weapon
介面,其中延伸出各種不同的武器,讓角色有能力去裝備這些東西;並且角色不需要進行初始化攻擊策略,而是由這些武器去自動鎖定攻擊策略!
筆者就按照前一篇講過的步驟嚴格執行。
首先,筆者建立 weapons
資料夾,並且新增 weapons/Weapon.ts
檔案,負責定義每個武器必須實作的特性:
Weapon
介面有幾個規格:
name
為武器名稱,為 readonly
模式availableRoles
控制的是武器可以被哪個職業裝備attackStrategy
則是武器綁定的是哪一種基礎攻擊策略另外,我們分別新增三種不同的武器:BasicSword
、BasicWand
以及 Dagger
。
接下來是在父類別進行參考點的建立。不過這一次跟前一篇不同的是 —— 原本可以讓角色自由切換攻擊策略 Attack
,這一次希望達到的目標則是:角色裝備武器的同時,攻擊策略根據 Weapon
的 attackStrategy
自動進行綁定。
主要是角色負責進行攻擊 attack
的動作,而 attack
早就在前一篇被實現了。
不過,本範例是需要藉由更換武器 Weapon
,因此必須設計的主要功能是 equip
方法 —— 負責接收 Weapon
類型的物件作為參數,藉以調整攻擊策略。
以上的程式碼,也利用了 availableRoles
進行武器能否被裝備在角色身上的檢測。
本範例寫的策略,自然而然是更換武器的概念 —— 我們可以在子類別初始化武器的動作。
不過這裡要注意的是 —— 原本選擇攻擊的策略已經被置換成藉由選擇武器就會自動進行攻擊策略的綁定,所以對於 Swordsman
與 Warlock
分別實踐之結果如下:
以上功能已經完成囉!我們開始進行驗收的動作。(以下程式碼編譯並執行結果如圖二)
圖二:除了可以切換掉武器外,也發現切換錯武器也會自動拋出例外呢!
圖三就是目前的 Character
、Attack
與 Weapon
之間的關係圖。
圖三:類別和介面有連結,使得類別跟不同介面綁定下的策略進行彈性的互換操作
不過,請不要被以上的實踐被死死地綁住 —— 設計一個系統的方式有很多種,重點在於要如何設計好物件跟策略的互動關係。
譬如,筆者也可以選擇不要讓角色 Character
跟 Attack
攻擊策略有連結,而必須讓角色藉由與武器 Weapon
的連結進行攻擊 attack
的動作!不過筆者想像中的架構結果可能會變成這樣。(如圖四)
必須藉由選擇的 Weapon
再去連結各種不同的攻擊策略,這樣做的好處是 —— 以 Warlock
為例,它除了可以選擇用匕首 Dagger
進行 MagicAttack
魔法攻擊外,也可以選擇 StabAttack
單純物理性地刺擊。
所以要讓策略模式的發揮方式非常多種,最終完全於你想讓系統能夠出現什麼樣的行為。
今天大致上再讓讀者更熟悉策略模式的好處跟彈性!最重要的就是:策略可以隨時隨地被切換、策略也可以同時被不同的類別重複使用。(前提是要正確地使用策略模式 —— 筆者知道這是廢話 XD)
下一篇,筆者要補充類別還沒講完的部分,那就是 —— 抽象類別~
請問AttackRef為什麼要用private?
通常設計成 private
成員的狀況是 -- 我們不希望使用者使用該成員喔
如果 attackRef
使用 public
就代表外面的人可能可以藉由竄改 attackRef
導致程序發生無法預知的狀況
再加上,如果我們儘量封裝好物件,避免洩露越多東西,有幾個好處:
public
成員就好感謝解答。當時單純覺得如果用public可以少打很多行程式。
請問文章中的 UML 關係圖是用什麼軟體做的呢,看起來好漂亮~~
用 Illustrator 慢慢刻的 XD
(抱歉有點晚回覆 XD,最近作者太忙)