设计模式分为:创建型,结构型和行为型三种设计模式;
策略模式干货知识点
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:使用配表的方式,替代客户端的类型输入。