温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C#设计模式如何实现

发布时间:2022-06-02 09:25:37 来源:亿速云 阅读:111 作者:iii 栏目:开发技术

这篇文章主要介绍“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();
        }
    }

    试着运行一下,

    C#设计模式如何实现

    看起来一切都好。

    加上存档

    虽然游戏可以正常运行,但是总感觉还是少了点什么。嗯,存档功能,一个游戏没有存档是不健全的,毕竟,人生虽然没有存档,但是游戏可是有的!让我们加上存档功能吧,首先想想怎么设计。

    需要存档的数据

    首先我们要明确,有哪些数据是需要存档的,在这个游戏中,玩家的生命值、攻击力、暴击率;怪兽的生命值、攻击力和丢失率,游戏的回合数,都是需要存储的对象。

    存档定义

    这是一个需要仔细思考的地方,一般来说,需要考虑以下几个地方:

    • 存档需要访问一些游戏中的私有字段,比如暴击率,需要在不破坏游戏封装的情况下实现这个功能

    • 存档自身需要实现信息隐藏,即除了游戏,其他类不应该访问存档的详细信息

    • 存档不应该和游戏存放在一起,以防不经意间游戏破坏了存档数据,应该有专门的类存放存档

    备忘录模式出场

    这个时候应该是主角出场的时候了。看看备忘录模式的定义

    在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态

    再看看UML,

    C#设计模式如何实现

    看起来完全符合我们的需求啊,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#设计模式如何实现

    看起来一切正常,这样我们就使用备忘录模式,完成了存档读档的功能。

    到此,关于“C#设计模式如何实现”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI