C# 状态模式

状态模式是一种行为设计模式,它使对象能够在内部状态改变时改变其行为。文章通过代码示例展示了如何使用状态模式来管理对象在不同状态下的行为,如在游戏AI中的应用,比如怪物在寻找、攻击、逃跑和恢复生命值等不同状态下的行为管理。这种模式可以将条件分支逻辑封装在不同的状态类中,简化代码并提高可维护性。
摘要由CSDN通过智能技术生成

概述

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

状态模式效果:

  1>、状态模式的本质是将条件语句的各个分支封装起来,从而实现了状态逻辑与动作的分离。当分支很多时,状态模式可以给代码的维护带来很大的便利。

  2>、多态性的实现。

  3>、状态转换的显示化。状态模式将状态的切换逻辑存放到状态对象中,可以实现状态的自动切换,使各个状态界限分明,相互独立。

  4>、采用分支结构时,Context 对象需要关心所有状态的切换逻辑,当分支越来越多时,复杂度也会越来越大。而状态模式中Context无需关心状态的切换逻辑,每个状态对象也只需关心状态的下一个可能状态的切换逻辑。


  状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑表示不同状态的一系列类中,可以把复杂的判断逻辑简化。状态模式的目的是为了将状态与不同状态下的行为进行分离,从而简化复杂的条件判断。

  状态模式主要适用场景:

  ◊ 一个对象的行为取决于它的状态,并且必须在运行时刻根据状态改变其行为;

  ◊ 一个操作中包含庞大的分支结构,并且这些分支决定于对象的状态。

结构图

代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 状态模式
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Context c = new Context(new ConcreteStateA()); 
            c.Request(); 
            c.Request();

            Console.ReadKey();
        }
    }

    public abstract class State
    {
        public abstract void Handle(Context context);
    }

    public class ConcreteStateA : State
    {
        public override void Handle(Context context)
        {
            context.State = new ConcreteStateB();
        }
    }

    public class ConcreteStateB : State
    {
        public override void Handle(Context context)
        {
            context.State = new ConcreteStateA();
        }
    }

    public class Context
    {
        public State State
        {
            get { return state; }
            set
            {
                state = value;
                Console.WriteLine("当前状态:" + state.GetType().Name);
            }
        }

        public void Request()
        {
            state.Handle(this);
        }

        private State state;
        public Context(State state)
        {
            this.State = state;
        }
    }
}

运行:

详解

下面我们来看下这三句打印是怎么出来的。

第一句打印 当前状态:ConcreteStateA 

在 Main 方法中,第一句代码:

Context c = new Context(new ConcreteStateA());

这句代码实例化了 Context 类,并在 Context 类的构造函数中,给属性 State 赋值了

然后就打印了 ConcreteStateA 的类名

第二句打印 当前状态:ConcreteStateB

这句的打印的来自下图这行代码

由于 Context 的 State 属性目前等于 ConcreteStateA 实例,所以就会调用 ConcreteStateA 的  Handle 方法,并将 自身的实例传递了过去

接下来我们看看 ConcreteStateA 的 Handle 方法

在调用了 Handle 方法后,在这里又对 State 状态做了一次实例化,所以又打印了 当前状态:ConcreteStateB

第三句的 当前状态:ConcreteStateA  打印和第二句同理。

实践

那么状态模式在实际开发中有那些应用呢?我就以游戏中怪物的 AI 为例子,假设怪物生命值是满血状态的话,那么就四处寻找目标,找到目标后,就切换成攻击状态,对主角攻击,然后玩家同时也对怪物发动了攻击,怪物生命值到了残血状态,那么就逃跑,并喝血瓶恢复生命值,并继续与玩家对战,这么一个简单的流程,下面看看要怎么写

为了方便,我就以 Winform 项目作为演示吧

界面如下,控件的名字可以看下面的代码,或者在后面的源码中查看

新建类  State

using System;

namespace 状态模式实践
{
    /// <summary>
    /// 状态抽象类
    /// </summary>
    public abstract class State
    {
        public abstract void Handle(Role role);
    }

    /// <summary>
    /// 怪物寻找状态
    /// </summary>
    public class MonsterFind : State
    {
        private Role Target { get; set; }

        public override void Handle(Role role)
        {
            if (role.HP <= 0)
            {
                Console.WriteLine("[MonsterFind]角色:{0} 已经死亡,无法执行", role.Type);
                return;
            }

            Console.WriteLine("[MonsterFind]角色:{0} 找到目标了,目标是:{1}", role.Type, Target.Type);
        }

        public MonsterFind(Role target)
        {
            Target = target;
        }
    }

    /// <summary>
    /// 怪物攻击状态
    /// </summary>
    public class MonsterAttack : State
    {
        private Role Target { get; set; }

        public override void Handle(Role role)
        {
            if(Target.HP <= 0)
            {
                Console.WriteLine("[MonsterAttack]角色:{0} 已经死亡,无法执行", Target.Type);
                return;
            }
            if (role.HP <= 0)
            {
                Console.WriteLine("[MonsterAttack]角色:{0} 已经死亡,无法执行", role.Type);
                return;
            }

            Console.WriteLine("[MonsterAttack]角色:{0} 攻击了目标:{1}", role.Type, Target.Type);
            Target.Injured(50);
        }     

        public MonsterAttack(Role target)
        {
            Target = target;
        }
    }

    /// <summary>
    /// 怪物逃离状态
    /// </summary>
    public class MonsterFlee : State
    {
        public override void Handle(Role role)
        {
            if (role.HP <= 0)
            {
                Console.WriteLine("[MonsterFlee]角色:{0} 已经死亡,无法执行", role.Type);
                return;
            }
            Console.WriteLine("[MonsterFlee]角色:{0} 逃离了", role.Type);
        }
    }

    /// <summary>
    /// 恢复生命值
    /// </summary>
    public class MonsterRecover : State
    {
        public override void Handle(Role role)
        {
            if (role.HP <= 0)
            {
                Console.WriteLine("[MonsterRecover]角色:{0} 已经死亡,无法恢复", role.Type);
                return;
            }

            if (role.HP + 100 > 700)
            {
                Console.WriteLine("[MonsterRecover]角色:{0} 超过了生命值上限", role.Type);
                return;
            }

            role.HP += 100;
            Console.WriteLine("[MonsterRecover]角色:{0} 恢复HP100,现在的HP:{1}", role.Type, role.HP);
        }
    }

    /// <summary>
    /// 玩家攻击
    /// </summary>
    public class PlayerAttack : State
    {
        public Role Target;

        public override void Handle(Role role)
        {
            if (role.HP <= 0)
            {
                Console.WriteLine("[PlayerAttack]{0}已经死亡,不能发动攻击", role.Type);
                return;
            }
            if(Target.HP <= 0)
            {
                Console.WriteLine("[PlayerAttack]{0}已经死亡,不能发动攻击", Target.Type);
                return;
            }

            Console.WriteLine("[PlayerAttack]角色:{0} 攻击了目标:{1}", role.Type, Target.Type);
            Target.Injured(150);
        }

        public PlayerAttack(Role role)
        {
            Target = role;
        }
    }
}

新建一个类 Role

using System;

namespace 状态模式实践
{
    /// <summary>
    /// 角色
    /// </summary>
    public abstract class Role
    {
        /// <summary>
        /// 角色类型
        /// </summary>
        public RoleType Type { get; set; }

        private State state;
        /// <summary>
        /// 状态
        /// </summary>
        public State States
        {
            get { return state; }
            set
            {
                state = value;
                state.Handle(this);
            }
        }

        /// <summary>
        /// 生命值
        /// </summary>
        public int HP { get; set; }

        /// <summary>
        /// 受到伤害
        /// </summary>
        public void Injured(int hp)
        {
            HP -= hp;
            if(HP <= 0) 
            {
                HP = 0;
                Console.WriteLine("[Role]{0} 已经死亡",Type);
                return;
            }
            Console.WriteLine("[Role]{0} 被攻击了,扣除 HP:{1},现在 HP:{2}", Type, hp, HP);
        }

        public Role(RoleType type, int hp)
        {
            Type = type;
            HP = hp;
        }
    }

    /// <summary>
    /// 角色类型
    /// </summary>
    public enum RoleType
    {
        None,
        玩家,
        怪物
    }
}

新建一个类 Monster

namespace 状态模式实践
{
    /// <summary>
    /// 怪物
    /// </summary>
    internal class Monster : Role
    {
        public Monster() : base(RoleType.怪物, 500)
        {
        }
    }
}

新建一个类 Player

namespace 状态模式实践
{
    /// <summary>
    /// 玩家
    /// </summary>
    internal class Player : Role
    {
        public Player() : base(RoleType.玩家, 500)
        {
        }
    }
}

Form1 代码

using System;
using System.Windows.Forms;

namespace 状态模式实践
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //玩家
        private Role PlayerRole = null;
        //怪物
        private Role MonsterRole = null;

        private void Form1_Load(object sender, EventArgs e)
        {
            PlayerRole = new Player();
            MonsterRole = new Monster();
        }

        /// <summary>
        /// 寻找
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Find_Click(object sender, EventArgs e)
        {
            MonsterRole.States = new MonsterFind(PlayerRole);
        }

        /// <summary>
        /// 攻击
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Attack_Click(object sender, EventArgs e)
        {
            MonsterRole.States = new MonsterAttack(PlayerRole);
        }

        /// <summary>
        /// 逃离状态
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Flee_Click(object sender, EventArgs e)
        {
            MonsterRole.States = new MonsterFlee();
        }

        /// <summary>
        /// 恢复
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Recover_Click(object sender, EventArgs e)
        {
            MonsterRole.States = new MonsterRecover();
        }

        /// <summary>
        /// 玩家攻击
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_PlayerAttack_Click(object sender, EventArgs e)
        {
            if(PlayerRole.HP <= 0)
            {
                Console.WriteLine("玩家已经死亡,不能做此操作");
                return;
            }

            PlayerRole.States = new PlayerAttack(MonsterRole);
        }
    }
}

测试

1.寻找

2.攻击

怪物攻击玩家

玩家攻击怪物

 3. 逃离

4.恢复

源码:点击下载

结束

如果这个帖子对你有所帮助,欢迎 关注 + 点赞 + 留言

end

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熊思宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值