设计模式中的每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动。
设计模式在类间关系这个粒度上给出常见问题的解决方案。属于软件工程中逻辑架构设计中相当重要的一环。
快速查阅各类设计模式使用场景可参考此文:设计模式大全。
一、策略模式
定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法的变化不会影响到使用算法的客户。
概述:策略模式将变化封装起来,使得策略使用环境(Context)与实际策略(ConcreteStrategy)分离。在程序运行过程中,面对实际的使用环境时,再决定 Context 使用什么样的 ConcreteStrategy。
1、核心思想
策略模式把角色的行为(算法)和角色(环境)分开。并将策略的选择权交给高层模块,在运行时才确定角色的具体行为。
2、类图
- Context :是策略的使用者(在 ContextInterface 中使用),拥有一个策略接口对象(图中为 object)。
- Strategy :策略接口,提供策略的使用方法。
- ConcreteStrategy :实际策略,是具体策略的实现者。
- Client :客户端,是实际策略与策略使用环境绑定的地点。
5、应用场景以及优缺点
1)应用场景
只要涉及到算法的封装、复用和切换都可以考虑使用策略模式。
2)优点
采用该模式可以方便地更换算法或者增加新的算法。避免了较难维护的多重选择条件选择语句。
3)缺点
缺点:客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法。
解决方案:搭配简单工厂模式。
缺点:客户端一次只能使用一个策略类,也就是说每个具体策略间相互独立。
解决方案:装饰模式(待实践)。
二、游戏应用
穿越火线战场上,玩家打落装备后可以跑过去捡起来使用,这个武器可能是M4A1-翔龙、AT15-沙丘或者是KAC锯式机枪。玩家射击时的射速、射程只跟武器有关,而跟玩家没有直接联系。此时将玩家作为环境类、具体武器作为具体策略类,采用策略模式即可实现该过程。
1、伪代码
////////////环境类///////////////////////
class 玩家{
武器 _weapon;
设置武器(weapon){
_weapon = weapon;
}
射击(){
_weapon->射击();
};
}
////////////策略类///////////////////////
class 武器{
射击();
}
class M4A1-翔龙: 武器{
射击(){
printf("翔龙射击");
};
}
class AT15-沙丘: 武器{
射击(){
printf("沙丘射击");
};
}
class KAC锯式机枪: 武器{
射击(){
printf("机枪扫射");
};
}
////////////客户端///////////////////////
...
玩家 player = new 玩家();
武器 weapon = new KAC锯式机枪();
player->设置武器(weapon);
...
player->射击();
...
2、点评
策略模式在该场景中的使用有一个很明显的缺点,穿越火线中的武器十分多样,把每一种武器都写成一个具体策略类显然是不现实的。笔者这样写是简便起见,方便理解。实际的设计应该是按照步枪、机枪、近战武器这样归为不同的策略类。
三、参考
C++设计模式之策略模式 (这篇文章把策略模式在游戏中的使用讲解地很好,本文主要由此处借鉴而来,感谢原文作者)
策略模式定义及其应用(以魂斗罗中英雄使用不同类型的子弹为例子介绍策略模式的使用)
奇幻RPG(角色技能 与 Strategy模式) (在策略模式的基础上稍微做了深化,更接近实际的游戏代码)
基于状态机的游戏框架(在游戏中,策略模式也能用于状态机管理,此文介绍了状态机的使用)