您好,登錄后才能下訂單哦!
這篇文章主要介紹“C#設計模式如何實現”,在日常操作中,相信很多人在C#設計模式如何實現問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”C#設計模式如何實現”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
這是一個簡單的打怪游戲,有玩家,有怪獸,玩家作為主角光環,有如下三個特殊能力
攻擊怪獸有暴擊幾率
有幾率回避怪獸攻擊
可以自己治療一定生命值
首先是角色類,角色類提供玩家和怪獸最基本的抽象,比如血量、攻擊力、攻擊和治療。(對于怪獸來說,治療是沒有提供實現的,壞人肯定不能再治療了)
class Character { public int HealthPoint { get; set; } public int AttackPoint { get; set; } public virtual void AttackChracter(Character opponent) { opponent.HealthPoint -= this.AttackPoint; if (opponent.HealthPoint < 0) { opponent.HealthPoint = 0; } } public virtual void Cure() { //故意留空給子類實現 } }
玩家實現了治療功能并且有暴擊幾率。
class Player : Character { private float playerCriticalPossible; public Player(float critical) { playerCriticalPossible = critical; } public override void AttackChracter(Character opponent) { base.AttackChracter(opponent); Console.WriteLine("Player Attacked Monster"); Random r = new Random(); bool critical = r.Next(0, 100) < playerCriticalPossible * 100; if (critical) { base.AttackChracter(opponent); Console.WriteLine("Player Attacked Monster again"); } } public override void Cure() { Random r = new Random(); HealthPoint += r.Next(5, 10); Console.WriteLine("Player cured himself"); } }
怪獸沒有治療能力但是有一定的幾率丟失攻擊目標。
class Monster : Character { private float monsterMissingPossible; public Monster(float missing) { monsterMissingPossible = missing; } public override void AttackChracter(Character opponent) { Random r = new Random(); bool missing = r.Next(0, 100) < monsterMissingPossible * 100; if (missing) { Console.WriteLine("Monster missed it"); } else { base.AttackChracter(opponent); Console.WriteLine("Monster Attacked player"); } } }
游戲類負責實例化玩家和怪獸、記錄回合數、判斷游戲是否結束,暴露可調用的公共方法給游戲操作類。
class Game { private Character m_player; private Character m_monster; private int m_round; private float playerCriticalPossible = 0.6f; private float monsterMissingPossible = 0.2f; public Game() { m_player = new Player(playerCriticalPossible) { HealthPoint = 15, AttackPoint = 2 }; m_monster = new Monster(monsterMissingPossible) { HealthPoint = 20, AttackPoint = 6 }; } public bool IsGameOver => m_monster.HealthPoint == 0 || m_player.HealthPoint == 0; public void AttackMonster() { m_player.AttackChracter(m_monster); } public void AttackPlayer() { m_monster.AttackChracter(m_player); } public void CurePlayer() { m_player.Cure(); } public void BeginNewRound() { m_round++; } public void ShowGameState() { Console.WriteLine("".PadLeft(20, '-')); Console.WriteLine("Round:{0}", m_round); Console.WriteLine("player health:{0}", "".PadLeft(m_player.HealthPoint, '*')); Console.WriteLine("monster health:{0}", "".PadLeft(m_monster.HealthPoint, '*')); } }
在我們這個簡易游戲中,沒有UI代碼,游戲操作類負責在用戶輸入和游戲中搭建一個橋梁,解釋用戶的輸入。
class GameRunner { private Game m_game; public GameRunner(Game game) { m_game = game; } public void Run() { while (!m_game.IsGameOver) { m_game.BeginNewRound(); bool validSelection = false; while (!validSelection) { m_game.ShowGameState(); Console.WriteLine("Make your choice: 1. attack 2. Cure"); var str = Console.ReadLine(); if (str.Length != 1) { continue; } switch (str[0]) { case '1': { validSelection = true; m_game.AttackMonster(); break; } case '2': { validSelection = true; m_game.CurePlayer(); break; } default: break; } } if(!m_game.IsGameOver) { m_game.AttackPlayer(); } } } }
客戶端的代碼就非常簡單了,只需要實例化一個游戲操作類,然后讓其運行就可以了。
class Program { static void Main(string[] args) { Game game = new Game(); GameRunner runner = new GameRunner(game); runner.Run(); } }
試著運行一下,
看起來一切都好。
雖然游戲可以正常運行,但是總感覺還是少了點什么。嗯,存檔功能,一個游戲沒有存檔是不健全的,畢竟,人生雖然沒有存檔,但是游戲可是有的!讓我們加上存檔功能吧,首先想想怎么設計。
首先我們要明確,有哪些數據是需要存檔的,在這個游戲中,玩家的生命值、攻擊力、暴擊率;怪獸的生命值、攻擊力和丟失率,游戲的回合數,都是需要存儲的對象。
這是一個需要仔細思考的地方,一般來說,需要考慮以下幾個地方:
存檔需要訪問一些游戲中的私有字段,比如暴擊率,需要在不破壞游戲封裝的情況下實現這個功能
存檔自身需要實現信息隱藏,即除了游戲,其他類不應該訪問存檔的詳細信息
存檔不應該和游戲存放在一起,以防不經意間游戲破壞了存檔數據,應該有專門的類存放存檔
這個時候應該是主角出場的時候了。看看備忘錄模式的定義
在不破壞封閉的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態。這樣以后就可將該對象恢復到原先保存的狀態
再看看UML,
看起來完全符合我們的需求啊,Originator就是游戲類,知道如何創造存檔和從存檔中恢復狀態,Memento類就是存檔類,Caretaker是一個新類,負責保存存檔。
經過思考,我們決定采取備忘錄模式,同時加入以下措施:
將存檔定義為游戲中的私有嵌套類,這樣存檔可以毫無壓力的訪問游戲中的私有字段,同時外界永遠沒有辦法去實例化或者嘗試通過轉型來獲得這個類,完美的保護了存檔類
存檔類是一個簡單的數據集合,不包含任何其他邏輯
添加一個存檔管理器,可以放在游戲操作類中,可以通過它看到我們當前有沒有存檔
存檔放在存檔管理器中
存檔實現一個空接口,在存檔管理器中以空接口形式出現,這樣外部類在訪問存檔的時候,僅能看到這個空接口。而在游戲類內部,我們在使用存檔之前先通過向下轉型實現類型轉換(是的,向下轉型不怎么好,但是偶爾可以用一下)
interface IGameSave { }
該類存放在game里面,無壓力地在不破壞封裝的情況下訪問game私有字段
private class GameSave : IGameSave { public int PlayerHealth { get; set; } public int PlayerAttack { get; set; } public float PlayerCritialAttackPossible { get; set; } public int MonsterHealth { get; set; } public int MonsterAttack { get; set; } public float MonsterMissingPossible { get; set; } public int GameRound { get; set; } }
在game中添加創建存檔和從存檔恢復的代碼,在從存檔恢復的時候,使用了向下轉型,因為從存檔管理器讀出來的只是空接口而已
public IGameSave CreateSave() { var save = new GameSave() { PlayerHealth = m_player.HealthPoint, PlayerAttack = m_player.AttackPoint, PlayerCritialAttackPossible = playerCriticalPossible, MonsterAttack = m_monster.AttackPoint, MonsterHealth = m_monster.HealthPoint, MonsterMissingPossible = monsterMissingPossible, GameRound = m_round }; Console.WriteLine("game saved"); return save; } public void RestoreFromGameSave(IGameSave gamesave) { GameSave save = gamesave as GameSave; if(save != null) { m_player = new Player(save.PlayerCritialAttackPossible) { HealthPoint = save.PlayerHealth, AttackPoint = save.PlayerAttack }; m_monster = new Player(save.MonsterMissingPossible) { HealthPoint = save.MonsterHealth, AttackPoint = save.MonsterAttack }; m_round = save.GameRound; } Console.WriteLine("game restored"); }
添加一個類專門管理存檔,此類非常簡單,只有一個存檔,要支持多存檔可以考慮使用List
class GameSaveStore { public IGameSave GameSave { get; set; } }
首先在游戲操作類中添加一個存檔管理器
private GameSaveStore m_gameSaveStore = new GameSaveStore();
接著修改Run方法添加用戶操作
public void Run() { while (!m_game.IsGameOver) { m_game.BeginNewRound(); bool validSelection = false; while (!validSelection) { m_game.ShowGameState(); Console.WriteLine("Make your choice: 1. attack 2. Cure 3. Save 4. Load"); var str = Console.ReadLine(); if (str.Length != 1) { continue; } switch (str[0]) { case '1': { validSelection = true; m_game.AttackMonster(); break; } case '2': { validSelection = true; m_game.CurePlayer(); break; } case '3': { validSelection = false; m_gameSaveStore.GameSave = m_game.CreateSave(); break; } case '4': { validSelection = false; if(m_gameSaveStore.GameSave == null) { Console.WriteLine("no save to load"); } else { m_game.RestoreFromGameSave(m_gameSaveStore.GameSave); } break; } default: break; } } if(!m_game.IsGameOver) { m_game.AttackPlayer(); } } }
注意,上面的3和4是新添加的存檔相關的操作。試著運行一下。
看起來一切正常,這樣我們就使用備忘錄模式,完成了存檔讀檔的功能。
到此,關于“C#設計模式如何實現”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。