<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
當老胡還是小胡的時候,跟隨團隊一起開發一款遊戲。這款遊戲是一款末日生存類遊戲,玩家可以
專案開發的很順利,我那時得到一個任務,是為遊戲做一個新手教學,在這個教學裡面,通過一系列步驟,引導新手玩家熟悉這個遊戲。遊戲設計給出的教學包含以下步驟
同時要求在不用的階段顯示不同的提示以正確引導玩家。考慮合成裝備算是高階玩家才會接觸到的功能,所以暫時不打算放在新手教學裡面。
當老大把任務交給我的時候,我感覺簡單爆了,不就寫一個新手教學麼,要求又那麼明確,應該要不了多少時間。於是,一個上午過後,我交出瞭如下程式碼。
首先用一個列舉,表示教學進行的不同程度
enum TutorialState { GetGold, GetIron, KillEnemy, LevelUp }
無需多言,封裝收集到的資源數、擊殺敵人數量、角色等級和一些升級介面等
class Player { private int ironNum; private int goldNum; private int enemyKilled; private int level; public int IronNum => ironNum; public int GoldNum => goldNum; public int EnemyKilled => enemyKilled; public int Level => level; public void CollectIron(int num) { ironNum += num; } public void CollectGold(int num) { goldNum += num; } public void KillEnemy() { enemyKilled++; } public void LevelUp() { level++; } }
定義一個教學類,包括
class GameTutorial { private TutorialState currentState; private Player player; public GameTutorial(Player player) { this.player = player; } public void ShowHelpDescription() { switch (currentState) { case TutorialState.GetGold: Console.WriteLine("Please follow instruction to get gold"); break; case TutorialState.GetIron: Console.WriteLine("Please follow instruction to get Iron"); break; case TutorialState.KillEnemy: Console.WriteLine("Please follow instruction to kill enemy"); break; case TutorialState.LevelUp: Console.WriteLine("Please follow instruction to Up your level"); break; default: throw new Exception("Not Support"); } } public void ValidateState() { switch (currentState) { case TutorialState.GetGold: { if (player.GoldNum > 0) { Console.WriteLine("Congratulations, you finished Gold Collect Phase"); currentState = TutorialState.GetIron; } else { Console.WriteLine("You need to collect gold"); } break; } case TutorialState.GetIron: { if (player.IronNum > 0) { Console.WriteLine("Congratulations, you finished Iron Collect Phase"); currentState = TutorialState.KillEnemy; } else { Console.WriteLine("You need to collect Iron"); } break; } case TutorialState.KillEnemy: { if (player.EnemyKilled > 0) { Console.WriteLine("Congratulations, you finished Enemy Kill Phase"); currentState = TutorialState.LevelUp; } else { Console.WriteLine("You need to kill enemy"); } break; } case TutorialState.LevelUp: { if (player.Level > 0) { Console.WriteLine("Congratulations, you finished the whole tutorial"); currentState = TutorialState.LevelUp; } else { Console.WriteLine("You need to level up"); } break; } default: throw new Exception("Not Support"); } } }
static void Main(string[] args) { Player player = new Player(); GameTutorial tutorial = new GameTutorial(player); tutorial.ShowHelpDescription(); tutorial.ValidateState(); //收集黃金 player.CollectGold(1); tutorial.ValidateState(); tutorial.ShowHelpDescription(); //收集木頭 player.CollectIron(1); tutorial.ValidateState(); tutorial.ShowHelpDescription(); //殺敵 player.KillEnemy(); tutorial.ValidateState(); tutorial.ShowHelpDescription(); //升級 player.LevelUp(); tutorial.ValidateState(); }
執行結果
看起來一切都好。。編寫的程式碼既能夠根據當前步驟顯示不同的提示,還可以成功的根據玩家的進度切換到下一個步驟。
於是,我自信滿滿的申請了code review,按照我的想法,這段程式碼通過code review應該是板上釘釘的事情,誰知,老大看到程式碼,差點沒背過氣去。。。稍微平復了一下心情之後,他給了我幾個靈魂拷問。
本來以為如此簡單的一個功能,沒想到還是有那麼多彎彎道道,只怪自己還是太年輕啊!最後他悠悠的告訴我,去看看狀態模式吧,想想這段程式碼可以怎麼重構。
物件擁有內在狀態,當內在狀態改變時允許其改變行為,這個物件看起來像改變了其類
有點意思,看來我們可以把教學的不同步驟抽象成不同的狀態,然後在各個狀態內部實現切換狀態和顯示幫助檔案的邏輯,這樣做的好處是
接著我們看看UML,
一目瞭然,在我們的例子裡面,state就是教學子步驟,context就是教學類,內部包含教學子步驟並轉發請求給教學子步驟,我們跟著來重構一下程式碼吧。
第一步我們需要刪除之前的列舉,取而代之的是一個抽象類當作狀態基礎類別,即,各個教學步驟類的基礎類別。注意,每個子狀態要自己負責狀態切換,所以我們需要教學類暴露介面以滿足這個功能。
abstract class TutorialState { public abstract void ShowHelpDescription(); public abstract void Validate(GameTutorial tutorial); }
重構教學類體現在以下方面
class GameTutorial { private TutorialState currentState; private Player player; public int PlayerIronNum => player.IronNum; public int PlayerLevel => player.Level; public int PlayerGoldNum => player.GoldNum; public int PlayerEnemyKilled => player.EnemyKilled; public void SetState(TutorialState state) { currentState = state; } public GameTutorial(Player player) { this.player = player; currentState = TutorialStateContext.GetGold; } public void ShowHelpDescription() { currentState.ShowHelpDescription(); } public void ValidateState() { currentState.Validate(this); } }
接著我們建立各個子狀態代表不同的教學步驟
class TutorialSateGetGold : TutorialState { public override void ShowHelpDescription() { Console.WriteLine("Please follow instruction to get gold"); } public override void Validate(GameTutorial tutorial) { if (tutorial.PlayerGoldNum > 0) { Console.WriteLine("Congratulations, you finished Gold Collect Phase"); tutorial.SetState(TutorialStateContext.GetIron); } else { Console.WriteLine("You need to collect gold"); } } } class TutorialStateGetIron : TutorialState { public override void ShowHelpDescription() { Console.WriteLine("Please follow instruction to get Iron"); } public override void Validate(GameTutorial tutorial) { if (tutorial.PlayerIronNum > 0) { Console.WriteLine("Congratulations, you finished Iron Collect Phase"); tutorial.SetState(TutorialStateContext.KillEnemy); } else { Console.WriteLine("You need to collect iron"); } } } class TutorialStateKillEnemy : TutorialState { public override void ShowHelpDescription() { Console.WriteLine("Please follow instruction to kill enemy"); } public override void Validate(GameTutorial tutorial) { if (tutorial.PlayerEnemyKilled > 0) { Console.WriteLine("Congratulations, you finished enemy kill Phase"); tutorial.SetState(TutorialStateContext.LevelUp); } else { Console.WriteLine("You need to collect kill enemy"); } } } class TutorialStateLevelUp : TutorialState { public override void ShowHelpDescription() { Console.WriteLine("Please follow instruction to level up"); } public override void Validate(GameTutorial tutorial) { if (tutorial.PlayerLevel > 0) { Console.WriteLine("Congratulations, you finished the whole tutorial"); } } }
這是模式中沒有提到的知識點,一般來說,為了避免大量的子狀態物件被建立,我們會構造一個狀態容器,以靜態變數的方式初始化需要使用的子狀態。
static class TutorialStateContext { public static TutorialState GetGold; public static TutorialState GetIron; public static TutorialState KillEnemy; public static TutorialState LevelUp; static TutorialStateContext() { GetGold = new TutorialSateGetGold(); GetIron = new TutorialStateGetIron(); KillEnemy = new TutorialStateKillEnemy(); LevelUp = new TutorialStateLevelUp(); } }
測試程式碼部分保持不變,直接執行,結果和原來一樣,重構成功。
以上就是C#中物件狀態模式 教學範例的詳細內容,更多關於C#物件狀態模式 的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45