设计模式系列之策略模式(分装策略)

设计模式分为:创建型,结构型和行为型三种设计模式;

策略模式干货知识点

1、策略模式属于行为型设计模式。
2、策略模式(Strategy):定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
3、解决内容:策略模式是用来封装策略的。但在实践中,我们发现,可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务逻辑,就可以考虑使用策略模式处理这种变化的可能性。
4、优点
1、避免使用多重条件语句
2、简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
3、策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的
4、策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。
5、策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。
5、使用场景
5.1、一个类定义了多种行为, 并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的S t r a t e g y 类中以代替这些条件语句。
5.2、算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。

策略模式属于行为型设计模式。

策略模式的结构图:

1、一个策略基类,多个不同实现。
2、一个策略上下文。
在这里插入图片描述

策略模式简单案例1:《游戏战斗逻辑》

场景:游戏战斗,有些要在客户端战斗,有些要在服务器战斗,那么就定义一个战斗逻辑的基类。再分别实现一个客户端的策略,一个战斗服的策略(还有其他的策略等等)。

对应上下文就是在初始化的时候传入一个战斗的类型类就可。不需要知道具体的策略,只要知道策略的框架,执行就可以。将策略分装。

#region 策略模式基础框架
namespace Strategy
{
    /// <summary>
    /// 策略基类
    /// </summary>
    public abstract class BattleSceneImp
    {
        public abstract void Start();
        public abstract void Update();
        public abstract void End();
    }

    /// <summary>
    /// 策略1
    /// </summary>
    public class BattleSceneImpClient : BattleSceneImp
    {
        public override void Start(){}
        public override void Update(){}
        public override void End(){}
    }

    /// <summary>
    /// 策略2
    /// </summary>
    public class BattleSceneImpServer : BattleSceneImp
    {
        public override void Start(){}
        public override void Update(){}
        public override void End(){}
    }

    /// <summary>
    /// 策略模式上下文
    /// </summary>
    public class BattleScene
    {
        public BattleSceneImp imp;

        public void StartScene( BattleSceneImp imp)
        {
            this.imp = imp;
            imp.Start();
        }

    }

    /// <summary>
    /// 客户端使用
    /// </summary>
    public class Client
    {
        public void Main()
        {
            BattleScene scene = new BattleScene();
            scene.StartScene(new BattleSceneImpClient());
        }
    }
}
#endregion

策略模式简单案例1(优化):

场景同上,进行一丢丢的优化(看实际情况)

#region 策略模式 + 简单工厂模式
namespace StrategyAndFactory
{
    /// <summary>
    /// 定义策略类型供客户端使用
    /// </summary>
    public enum EBattleType
    {
        Client,
        Server,
    }

    /// <summary>
    /// 策略模式基类
    /// </summary>
    public abstract class BattleSceneImp
    {
        public abstract void Start();
        public abstract void Update();
        public abstract void End();
    }

    /// <summary>
    /// 策略1
    /// </summary>
    public class BattleSceneImpClient : BattleSceneImp
    {
        public override void Start()
        {
            Debug.LogError("client start...");
        }
        public override void Update(){}
        public override void End(){}
    }

    /// <summary>
    /// 策略2
    /// </summary>
    public class BattleSceneImpServer : BattleSceneImp
    {
        public override void Start()
        {
            Debug.LogError("server start...");
        }
        public override void Update(){}
        public override void End(){}
    }

    /// <summary>
    /// 策略模式上下文
    /// </summary>
    public class BattleScene
    {
        public BattleSceneImp imp;

        public void StartScene(EBattleType battleType)
        {
            switch(battleType)
            {
                case EBattleType.Client: 
                    imp = new BattleSceneImpClient();
                    break;
                case EBattleType.Server:
                    imp = new BattleSceneImpServer();
                    break;
            }

            imp.Start();
        }
    }

    /// <summary>
    /// 客户端使用,只传递类型,不需要知道具体的实现类是什么
    /// </summary>
    public class Client
    {
        public void Main()
        {
            BattleScene scene = new BattleScene();
            scene.StartScene(EBattleType.Client);
        }
    }
}

#endregion

策略模式简单案例2:《游戏技能选取目标逻辑》

场景:游戏战斗,释放技能选择伤害目标,不同的技能伤害模式不同,有的是扇形,有的是直线,有的是圆形。进行策略封装。

#region 策略模式之分装技能选取目标策略

namespace StartegySkill
{
    /// <summary>
    /// 选取目标策略接口
    /// </summary>
    public interface IAttackSelector
    {
        /// <summary>
        /// 根据策略选取目标并返回
        /// </summary>
        /// <param name="skillData">技能数据</param>
        /// <param name="target">目标</param>
        /// <returns></returns>
        GameObject[] SelectTarget(SkillData skillData, Transform target);
    } 

    /// <summary>
    /// 圆形选目标策略1
    /// </summary>
    public class CircleAttackSelectot : IAttackSelector
    {
        public GameObject[] SelectTarget(SkillData skillData, Transform target)
        {
            //实现圆形选取目标的逻辑
            return null;
        } 
    }

    /// <summary>
    /// 扇形选目标策略2
    /// </summary>
    public class SectorAccackSelector : IAttackSelector
    {
        public GameObject[] SelectTarget(SkillData skillData, Transform target)
        {
            //实现扇形选取目标的逻辑
            return null;
        }
    }

    /// <summary>
    /// 技能释放类,上下文
    /// </summary>
    public class SkillDeployer
    {
        public IAttackSelector attackSelector;
        public SkillData m_SkillData;
        public SkillData skillData
        {
            set
            {
                m_SkillData = value;
                switch(value.mode)
                {
                    case EDamageMode.Circle:
                        attackSelector = new CircleAttackSelectot();
                        break;
                    case EDamageMode.Sector:
                        attackSelector = new SectorAccackSelector();
                        break;
                }
            }
            get
            {
                return m_SkillData;
            }
        }

        public void UseSkill(SkillData skill)
        {
            this.skillData = skill;
            Transform target = null;
            m_SkillData.targets = attackSelector.SelectTarget(m_SkillData, target);
        }
    }

    /// <summary>
    /// 伤害模式
    /// </summary>
    public enum EDamageMode
    {
        Circle,
        Sector,
        None,
    }

    /// <summary>
    /// 技能数据类
    /// </summary>
    public class SkillData
    {
        public int skillId;

        public GameObject[] targets;

        public EDamageMode mode;
    }

    /// <summary>
    /// 客户端简单调用
    /// </summary>
    public class Client
    {
        public void Main()
        {
            SkillData skill = new SkillData();
            SkillDeployer deployer = new SkillDeployer();
            deployer.UseSkill(skill);
        }
    }
}

#endregion

策略模式还可以根据需求继续优化:

优化1:使用反射技术
,去掉Switch-case。
优化2:使用配表的方式,替代客户端的类型输入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值