设计模式 - 策略模式
策略模式
含义:定义了算法家族,并分别封装起来,让他们之间可以相互替换。也可以说:一个类的行为或其算法可以在运行时改变
实现过程:
- 概念性:创建抽象策略接口,所有具体策略类都继承该接口,并实现各自算法;创建Context上下文负责对接客户端与各策略类
- 比喻:存在火车、高铁、飞机三种具体交通策略方式,三者都存在于交通枢纽Context中,乘客只需要告诉枢纽他需要的交通方式,枢纽会为乘客提供具体的出行服务
- 备注:
- Context 上下文:负责和具体的策略实现交互。通常Context对象会持有一个真正的策略实现对象,并具备设置策略对象、调用策略的方法
优缺点:
- 优点:
- 策略算法动态切换便捷
- 扩展性良好(新增的具体策略类通过继承抽象策略类并实现自身方法即可使用)
- 简化单元测试(可逐一对各具体策略类进行测试)
- 有效减少条件判断语句
- 缺点:
- 每种策略算法即是一个类,造成类数量庞大
- 具体策略类都需要对外暴露(Context和客户端都需要知道)
适用场景:
- 系统中存在多个特征相似的类(火车、高铁、飞机都属于交通方式类;UE4、U3D、Cocos都属于游戏引擎类 ...)
- 系统需要动态地在算法家族中选择执行某一算法(没钱时选择火车,有钱时选择飞机)
项目示例:
打游戏时,有三种游戏输入设备(键盘、Xbox手柄、PS4手柄)供玩家选择,玩家根据自身条件选择某一设备进行游戏:
// 游戏输入设备(抽象策略类):
// ------------------------
public abstract class InputMode
{
public abstract void Play();
}
// 具体游戏输入设备(具体策略类):
// ---------------------------
public class Keyboard : InputMode
{
public override void Play()
{
Console.WriteLine("使用 Keyboard 进行游戏!");
}
}
public class Xbox : InputMode
{
public override void Play()
{
Console.WriteLine("使用 Xbox 进行游戏!");
}
}
public class PS4 : InputMode
{
public override void Play()
{
Console.WriteLine("使用 PS4 进行游戏!");
}
}
// Context对象:随着策略对象改变而改变
// --------------------------------
public class PlayContext
{
//当前游戏输入设备(策略实现对象)
InputMode myInputMode;
//构造函数:初始化当前游戏输入设备
public PlayContext(InputMode inputMode)
{
this.myInputMode = inputMode;
}
//调用游戏输入设备类中的方法
public void PlayInTheMode()
{
myInputMode.Play();
}
}
// 玩家(客户端):
// --------------
class Player
{
static void Main(string[] args)
{
PlayContext playContext;
playContext = new PlayContext(new Keyboard());
playContext.PlayInTheMode(); //使用 Keyboard 进行游戏!
playContext = new PlayContext(new Xbox());
playContext.PlayInTheMode(); //使用 Xbox 进行游戏!
playContext = new PlayContext(new PS4());
playContext.PlayInTheMode(); //使用 PS4 进行游戏!
}
}