溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C#設(shè)計模式如何實現(xiàn)

發(fā)布時間:2022-06-02 09:25:37 來源:億速云 閱讀:122 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“C#設(shè)計模式如何實現(xiàn)”,在日常操作中,相信很多人在C#設(shè)計模式如何實現(xiàn)問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”C#設(shè)計模式如何實現(xiàn)”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

    游戲背景

    這是一個簡單的打怪游戲,有玩家,有怪獸,玩家作為主角光環(huán),有如下三個特殊能力

    • 攻擊怪獸有暴擊幾率

    • 有幾率回避怪獸攻擊

    • 可以自己治療一定生命值

    游戲?qū)崿F(xiàn)

    角色類

    角色基類

    首先是角色類,角色類提供玩家和怪獸最基本的抽象,比如血量、攻擊力、攻擊和治療。(對于怪獸來說,治療是沒有提供實現(xiàn)的,壞人肯定不能再治療了)

    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()
        {
    		//故意留空給子類實現(xiàn)
        }
    }

    玩家類

    玩家實現(xiàn)了治療功能并且有暴擊幾率。

    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");
            }
        }
    }

    游戲類

    游戲類負責(zé)實例化玩家和怪獸、記錄回合數(shù)、判斷游戲是否結(jié)束,暴露可調(diào)用的公共方法給游戲操作類。

    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代碼,游戲操作類負責(zé)在用戶輸入和游戲中搭建一個橋梁,解釋用戶的輸入。

    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();
        }
    }

    試著運行一下,

    C#設(shè)計模式如何實現(xiàn)

    看起來一切都好。

    加上存檔

    雖然游戲可以正常運行,但是總感覺還是少了點什么。嗯,存檔功能,一個游戲沒有存檔是不健全的,畢竟,人生雖然沒有存檔,但是游戲可是有的!讓我們加上存檔功能吧,首先想想怎么設(shè)計。

    需要存檔的數(shù)據(jù)

    首先我們要明確,有哪些數(shù)據(jù)是需要存檔的,在這個游戲中,玩家的生命值、攻擊力、暴擊率;怪獸的生命值、攻擊力和丟失率,游戲的回合數(shù),都是需要存儲的對象。

    存檔定義

    這是一個需要仔細思考的地方,一般來說,需要考慮以下幾個地方:

    • 存檔需要訪問一些游戲中的私有字段,比如暴擊率,需要在不破壞游戲封裝的情況下實現(xiàn)這個功能

    • 存檔自身需要實現(xiàn)信息隱藏,即除了游戲,其他類不應(yīng)該訪問存檔的詳細信息

    • 存檔不應(yīng)該和游戲存放在一起,以防不經(jīng)意間游戲破壞了存檔數(shù)據(jù),應(yīng)該有專門的類存放存檔

    備忘錄模式出場

    這個時候應(yīng)該是主角出場的時候了??纯磦渫浤J降亩x

    在不破壞封閉的前提下,捕獲一個對象的內(nèi)部狀態(tài),并在該對象之外保存這個狀態(tài)。這樣以后就可將該對象恢復(fù)到原先保存的狀態(tài)

    再看看UML,

    C#設(shè)計模式如何實現(xiàn)

    看起來完全符合我們的需求啊,Originator就是游戲類,知道如何創(chuàng)造存檔和從存檔中恢復(fù)狀態(tài),Memento類就是存檔類,Caretaker是一個新類,負責(zé)保存存檔。

    經(jīng)過思考,我們決定采取備忘錄模式,同時加入以下措施:

    • 將存檔定義為游戲中的私有嵌套類,這樣存檔可以毫無壓力的訪問游戲中的私有字段,同時外界永遠沒有辦法去實例化或者嘗試通過轉(zhuǎn)型來獲得這個類,完美的保護了存檔類

    • 存檔類是一個簡單的數(shù)據(jù)集合,不包含任何其他邏輯

    • 添加一個存檔管理器,可以放在游戲操作類中,可以通過它看到我們當(dāng)前有沒有存檔

    • 存檔放在存檔管理器中

    • 存檔實現(xiàn)一個空接口,在存檔管理器中以空接口形式出現(xiàn),這樣外部類在訪問存檔的時候,僅能看到這個空接口。而在游戲類內(nèi)部,我們在使用存檔之前先通過向下轉(zhuǎn)型實現(xiàn)類型轉(zhuǎn)換(是的,向下轉(zhuǎn)型不怎么好,但是偶爾可以用一下)

    空接口

    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; }
    }

    創(chuàng)建存檔和從存檔恢復(fù)

    在game中添加創(chuàng)建存檔和從存檔恢復(fù)的代碼,在從存檔恢復(fù)的時候,使用了向下轉(zhuǎn)型,因為從存檔管理器讀出來的只是空接口而已

    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是新添加的存檔相關(guān)的操作。試著運行一下。

    C#設(shè)計模式如何實現(xiàn)

    看起來一切正常,這樣我們就使用備忘錄模式,完成了存檔讀檔的功能。

    到此,關(guān)于“C#設(shè)計模式如何實現(xiàn)”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

    向AI問一下細節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI