您的问题似乎不完整,您是想询问关于C语言编程的某个具体问题吗?比如C语言的语法、编程技巧、项目开发等。请提供更具体的信息,这样我才能给出更准确的回答。

2026-03-31 09:551阅读0评论SEO基础
  • 内容介绍
  • 相关推荐

本文共计2666个文字,预计阅读时间需要11分钟。

您的问题似乎不完整,您是想询问关于C语言编程的某个具体问题吗?比如C语言的语法、编程技巧、项目开发等。请提供更具体的信息,这样我才能给出更准确的回答。

目录+ 真实事件+ 定义枚举+ 教程进度表示+ 定义角色类+ 定义角色类+ 测试代码+ 状态模式出场+ 定义+ 代码重构+ 创建状态基类+ 重建教程类+ 创建各个子状态+ 添加状态容器+ 结束语+ 真实事件+ 当老人

目录
  • 真实的故事
  • 定义枚举表示教程进度
  • 定义角色类
  • 定义教程类
    • 测试代码
  • 状态模式出场
    • 定义
  • 代码重构
    • 创建状态基类
    • 重构教程类
    • 创建各个子状态
    • 添加状态容器
  • 结语

    真实的故事

    当老胡还是小胡的时候,跟随团队一起开发一款游戏。这款游戏是一款末日生存类游戏,玩家可以

    • 收集资源,两种,一种金子,一种铁。
    • 升级自身
    • 击杀敌人
    • 用资源合成装备

    项目开发的很顺利,我那时得到一个任务,是为游戏做一个新手教程,在这个教程里面,通过一系列步骤,引导新手玩家熟悉这个游戏。游戏设计给出的教程包含以下步骤

    • 收集金子
    • 收集铁
    • 击杀敌人
    • 升级

    同时要求在不用的阶段显示不同的提示以正确引导玩家。考虑合成装备算是高级玩家才会接触到的功能,所以暂时不打算放在新手教程里面。

    当老大把任务交给我的时候,我感觉简单爆了,不就写一个新手教程么,要求又那么明确,应该要不了多少时间。于是,一个上午过后,我交出了如下代码。

    定义枚举表示教程进度

    首先用一个枚举,表示教程进行的不同程度

    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应该是板上钉钉的事情,谁知,老大看到代码,差点没背过气去。。。稍微平复了一下心情之后,他给了我几个灵魂拷问。

    • GameTutorial需要知道各个步骤的满足条件和提示,它是不是知道的太多了?这符合迪米特法则吗?
    • 如果我们游戏之后新增一个教程步骤,指导玩家升级武器,是不是GameTutorial需要修改?能有办法规避这种新增的改动吗?
    • 如果我们要修改现在的教程步骤之间的顺序关系,GameTutorial是不是又不能避免要被动刀?能有办法尽量减少这种修改的工作量吗?
    • Switch case 在现有的情况下已经如此长,如果我们再加入新的步骤,这个方法会变成又臭又长的裹脚布吗?

    本来以为如此简单的一个功能,没想到还是有那么多弯弯道道,只怪自己还是太年轻啊!最后他悠悠的告诉我,去看看状态模式吧,想想这段代码可以怎么重构。

    状态模式出场

    定义

    对象拥有内在状态,当内在状态改变时允许其改变行为,这个对象看起来像改变了其类

    有点意思,看来我们可以把教程的不同步骤抽象成不同的状态,然后在各个状态内部实现切换状态和显示帮助文档的逻辑,这样做的好处是

    • 符合迪米特法则,把各个步骤所对应的逻辑推迟到子类,教程类就不需要了解每个步骤的逻辑细节,同时隔离了教程类和状态类,确保状态类的修改不会影响教程类
    • 符合开闭原则,如果新添加步骤,我们仅仅需要添加步骤子类并修改相邻的步骤切换逻辑,教程类无需任何改动

    接着我们看看UML,

    一目了然,在我们的例子里面,state就是教程子步骤,context就是教程类,内部包含教程子步骤并转发请求给教程子步骤,我们跟着来重构一下代码吧。

    您的问题似乎不完整,您是想询问关于C语言编程的某个具体问题吗?比如C语言的语法、编程技巧、项目开发等。请提供更具体的信息,这样我才能给出更准确的回答。

    代码重构

    创建状态基类

    第一步我们需要删除之前的枚举,取而代之的是一个抽象类当作状态基类,即,各个教程步骤类的基类。注意,每个子状态要自己负责状态切换,所以我们需要教程类暴露接口以满足这个功能。

    abstract class TutorialState { public abstract void ShowHelpDescription(); public abstract void Validate(GameTutorial tutorial); }

    重构教程类

    重构教程类体现在以下方面

    • 添加内部状态表面当前处于哪个步骤,在构造函数中给予初始值
    • 暴露接口以让子状态能修改当前状态以完成状态切换
    • 因为需要子状态能访问玩家当前数据以判断是否能切换状态,需要新加接口以避免方法链
    • 修改ShowHelpDescription和ValidateState的逻辑,直接转发方法调用至当前状态

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

    测试代码部分保持不变,直接运行,结果和原来一样,重构成功。

    结语

    • 这就是状态模式和它的使用场景,比较一下重构前和重构后的代码,发现代码通过重构满足了开闭原则和迪米特法则,相信重构后的代码能通过code review吧。_
    • 不过状态模式虽然好,也有自己的缺点,因为需要一个子类对应一个子状态,那么子状态太多的时候,就会出现类爆炸的情况。还请大家多注意。
    • 作为行为模式之一的状态模式,在日常开发中出现的频率还是挺高的,比如游戏中经常用到的状态机,就是状态模式的一种应用场景,大家在平时工作中保持善于观察的眼睛,就能学到更多的东西。

    以上就是C#中对象状态模式 教程示例的详细内容,更多关于C#对象状态模式 的资料请关注自由互联其它相关文章!

    本文共计2666个文字,预计阅读时间需要11分钟。

    您的问题似乎不完整,您是想询问关于C语言编程的某个具体问题吗?比如C语言的语法、编程技巧、项目开发等。请提供更具体的信息,这样我才能给出更准确的回答。

    目录+ 真实事件+ 定义枚举+ 教程进度表示+ 定义角色类+ 定义角色类+ 测试代码+ 状态模式出场+ 定义+ 代码重构+ 创建状态基类+ 重建教程类+ 创建各个子状态+ 添加状态容器+ 结束语+ 真实事件+ 当老人

    目录
    • 真实的故事
    • 定义枚举表示教程进度
    • 定义角色类
    • 定义教程类
      • 测试代码
    • 状态模式出场
      • 定义
    • 代码重构
      • 创建状态基类
      • 重构教程类
      • 创建各个子状态
      • 添加状态容器
    • 结语

      真实的故事

      当老胡还是小胡的时候,跟随团队一起开发一款游戏。这款游戏是一款末日生存类游戏,玩家可以

      • 收集资源,两种,一种金子,一种铁。
      • 升级自身
      • 击杀敌人
      • 用资源合成装备

      项目开发的很顺利,我那时得到一个任务,是为游戏做一个新手教程,在这个教程里面,通过一系列步骤,引导新手玩家熟悉这个游戏。游戏设计给出的教程包含以下步骤

      • 收集金子
      • 收集铁
      • 击杀敌人
      • 升级

      同时要求在不用的阶段显示不同的提示以正确引导玩家。考虑合成装备算是高级玩家才会接触到的功能,所以暂时不打算放在新手教程里面。

      当老大把任务交给我的时候,我感觉简单爆了,不就写一个新手教程么,要求又那么明确,应该要不了多少时间。于是,一个上午过后,我交出了如下代码。

      定义枚举表示教程进度

      首先用一个枚举,表示教程进行的不同程度

      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应该是板上钉钉的事情,谁知,老大看到代码,差点没背过气去。。。稍微平复了一下心情之后,他给了我几个灵魂拷问。

      • GameTutorial需要知道各个步骤的满足条件和提示,它是不是知道的太多了?这符合迪米特法则吗?
      • 如果我们游戏之后新增一个教程步骤,指导玩家升级武器,是不是GameTutorial需要修改?能有办法规避这种新增的改动吗?
      • 如果我们要修改现在的教程步骤之间的顺序关系,GameTutorial是不是又不能避免要被动刀?能有办法尽量减少这种修改的工作量吗?
      • Switch case 在现有的情况下已经如此长,如果我们再加入新的步骤,这个方法会变成又臭又长的裹脚布吗?

      本来以为如此简单的一个功能,没想到还是有那么多弯弯道道,只怪自己还是太年轻啊!最后他悠悠的告诉我,去看看状态模式吧,想想这段代码可以怎么重构。

      状态模式出场

      定义

      对象拥有内在状态,当内在状态改变时允许其改变行为,这个对象看起来像改变了其类

      有点意思,看来我们可以把教程的不同步骤抽象成不同的状态,然后在各个状态内部实现切换状态和显示帮助文档的逻辑,这样做的好处是

      • 符合迪米特法则,把各个步骤所对应的逻辑推迟到子类,教程类就不需要了解每个步骤的逻辑细节,同时隔离了教程类和状态类,确保状态类的修改不会影响教程类
      • 符合开闭原则,如果新添加步骤,我们仅仅需要添加步骤子类并修改相邻的步骤切换逻辑,教程类无需任何改动

      接着我们看看UML,

      一目了然,在我们的例子里面,state就是教程子步骤,context就是教程类,内部包含教程子步骤并转发请求给教程子步骤,我们跟着来重构一下代码吧。

      您的问题似乎不完整,您是想询问关于C语言编程的某个具体问题吗?比如C语言的语法、编程技巧、项目开发等。请提供更具体的信息,这样我才能给出更准确的回答。

      代码重构

      创建状态基类

      第一步我们需要删除之前的枚举,取而代之的是一个抽象类当作状态基类,即,各个教程步骤类的基类。注意,每个子状态要自己负责状态切换,所以我们需要教程类暴露接口以满足这个功能。

      abstract class TutorialState { public abstract void ShowHelpDescription(); public abstract void Validate(GameTutorial tutorial); }

      重构教程类

      重构教程类体现在以下方面

      • 添加内部状态表面当前处于哪个步骤,在构造函数中给予初始值
      • 暴露接口以让子状态能修改当前状态以完成状态切换
      • 因为需要子状态能访问玩家当前数据以判断是否能切换状态,需要新加接口以避免方法链
      • 修改ShowHelpDescription和ValidateState的逻辑,直接转发方法调用至当前状态

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

      测试代码部分保持不变,直接运行,结果和原来一样,重构成功。

      结语

      • 这就是状态模式和它的使用场景,比较一下重构前和重构后的代码,发现代码通过重构满足了开闭原则和迪米特法则,相信重构后的代码能通过code review吧。_
      • 不过状态模式虽然好,也有自己的缺点,因为需要一个子类对应一个子状态,那么子状态太多的时候,就会出现类爆炸的情况。还请大家多注意。
      • 作为行为模式之一的状态模式,在日常开发中出现的频率还是挺高的,比如游戏中经常用到的状态机,就是状态模式的一种应用场景,大家在平时工作中保持善于观察的眼睛,就能学到更多的东西。

      以上就是C#中对象状态模式 教程示例的详细内容,更多关于C#对象状态模式 的资料请关注自由互联其它相关文章!