返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C#备忘录人生存档的设计模式实例
  • 900
分享到

C#备忘录人生存档的设计模式实例

2024-04-02 19:04:59 900人浏览 安东尼
摘要

目录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#备忘录设计模式的资料请关注编程网其它相关文章!

--结束END--

本文标题: C#备忘录人生存档的设计模式实例

本文链接: https://lsjlt.com/news/150392.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C#备忘录人生存档的设计模式实例
    目录C#备忘录设计模式游戏背景游戏实现角色类角色基类玩家类怪兽类游戏类游戏操作类客户端加上存档需要存档的数据存档定义备忘录模式出场空接口私有嵌套存档类创建存档和从存档恢复存档管理器类...
    99+
    2024-04-02
  • Python设计模式中的备忘录模式
    目录备忘录模式应用场景代码示例总结备忘录模式 备忘录模式,在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。 简单来...
    99+
    2024-04-02
  • Java设计模式之备忘录模式
    无论是我们在使用word还是记事本,系统都会为我们提供撤销的功能,这几乎是人人都会使用到的功能,而在我们实际开发中,会不会存在一个很复杂的对象,当更改了其中的某一个属性以后,也提供撤...
    99+
    2022-11-13
    Java 设计模式 备忘录模式
  • Java设计模式之java备忘录模式详解
    目录引言备忘录模式(Memento Pattern)角色为什么会出现守护者对象(负责人)?备忘录模式实现框架下棋案例备忘录模式总结优点缺点适用场景注意细节参考文章总结引言 备忘录模式...
    99+
    2024-04-02
  • 行为型设计模式 - 备忘录模式详解
    |0基本介绍备忘录模式(Memento Pattern):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存的状态2|0模式结构Originator(发起者):记录当前的状态,负责创...
    99+
    2023-06-04
  • Java设计模式之备忘录模式实现对象状态的保存和恢复
    目录介绍实现备忘录类发起人类管理者类测试总结优点缺点应用场景介绍 备忘录模式(Memento Pattern)是一种行为型设计模式,它允许在不破坏封装性的前提下,捕获并保存一个对象的...
    99+
    2023-05-17
    Java设计模式 Java备忘录模式
  • .Net行为型设计模式之备忘录模式(Memento)
    目录一、动机(Motivate)二、意图(Intent)三、结构图(Structure)四、模式的组成五、备忘录模式的代码实现六、备忘录模式的实现要点:1、备忘录模式的主要优点有:2...
    99+
    2024-04-02
  • 深入理解Java设计模式之备忘录模式
    目录一、什么是备忘录模式二、备忘录模式的结构三、备忘录模式的使用场景四、备忘录模式的优缺点五、备忘录模式的实现总结一、什么是备忘录模式 定义:在不破坏封闭的前提下,捕获一个对象的内部...
    99+
    2024-04-02
  • Java设计模式初识之备忘录模式详解
    目录简介典型实现总结优点缺点适用场景源码简介 备忘录设计模式(Memento Design Pattern)也叫作快照(Snapshot)模式,主要用于实现防丢失、撤销、恢复等功能。...
    99+
    2022-11-13
    Java 设计模式 备忘录模式 Java 备忘录模式 Java 设计模式
  • .Net行为型设计模式之备忘录模式怎么实现
    这篇文章主要讲解了“.Net行为型设计模式之备忘录模式怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“.Net行为型设计模式之备忘录模式怎么实现”吧!一、动机(Motivate)我们看...
    99+
    2023-06-30
  • 怎样深入理解Java设计模式的备忘录模式
    本篇文章为大家展示了怎样深入理解Java设计模式的备忘录模式,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一、什么是备忘录模式定义:在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这...
    99+
    2023-06-25
  • Java设计模式之备忘录模式_动力节点Java学院
    定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存的状态类型:行为类类图:        我们在编程的时候...
    99+
    2023-05-31
    备忘录模式 java 设计模式
  • JAVA设计模式之备忘录模式原理与用法详解
    本文实例讲述了JAVA设计模式之备忘录模式。分享给大家供大家参考,具体如下:备忘录模式:又叫做快照模式,指在不破坏封装性的前提下,获取到一个对象的内部状态,并在对象之外记录或保存这个状态。在有需要的时候可将该对象恢复到原先保存的状态。我们相...
    99+
    2023-05-31
    java 设计模式 备忘录模式
  • C#设计模式实现之生成器模式和责任链模式
    目录生成器设计类图: 实现代码:优点:用途与缺点:责任链设计类图:实现代码:优点:用途和缺点:总结生成器 生成器模式:封装一个产品的构造过程,并允许按步骤构造。 现又一个...
    99+
    2024-04-02
  • C#设计模式之装饰器模式实例详解
    最近踢了场球,9人制比赛,上半场我们采用防守阵型效果不佳,下半场采用进攻阵型取得了比赛的主动。我们上下半场所采取的策略,似乎可以用"装饰器"模式实现一遍。 首先肯...
    99+
    2024-04-02
  • C++设计模式之简单工厂模式的实现示例
    前言 在我们要使用一个对象时,就必须通过类来实例化对象,也就是需要new一个对象。在new的过程是非常复杂的,要经过读文件->解析文本->创建对象->给属性设值等过...
    99+
    2024-04-02
  • Java设计模式的单例模式实例分析
    本文小编为大家详细介绍“Java设计模式的单例模式实例分析”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java设计模式的单例模式实例分析”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。什么是单例模式单例模式(S...
    99+
    2023-06-29
  • java 中设计模式(装饰设计模式)的实例详解
    java 中设计模式(装饰设计模式)的实例详解应用场景:在不对原有对象类进行修改的基础上,给一个或多个已有的类对象提供增强额外的功能. 我觉得可以从字面理解,装饰,装饰房子。房子可以看成原有的类。等于你把一个已经建好的房子按照自己的想法再装...
    99+
    2023-05-31
    java 装饰模式 ava
  • 设计模式在C++中的应用案例
    是的,设计模式在 c++++ 中有广泛应用。观察者模式是一种一对一关系,其中一个对象(主体)管理依赖对象(观察者)并通知它们状态变化。在这个示例中,天气数据(主体)通知显示屏(观察者)状...
    99+
    2024-05-14
    c++ 设计模式
  • Java设计模式的单例模式如何实现
    这篇文章主要介绍了Java设计模式的单例模式如何实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java设计模式的单例模式如何实现文章都会有所收获,下面我们一起来看看吧。单例模式单例模式顾名思义就是单一的实例...
    99+
    2023-06-29
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作