策略模式:定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
比如超市收银软件,针对超市的不同销售策略(打八折、满300减50等),需要运用不同的算法。策略模式就可以适用于这种场合。这里打折、满减等作为一个算法族,继承自同一的父类;这些算法作为程序中经常变化的部分,被封装起来并独立于软件主体;同时提供一种方式,让软件主体可以动态的改变使用的算法。
策略模式的UML类图如下:
这里的Strategy抽象类是ConcreteStrategyA和ConcreteStrategyB的父类,它们构成了一个算法族,子类重写了父类的算法实现方法AlgorithmInterface();Context类属于软件主体部分,决定使用的具体算法;Context类与Strategy为聚合关系(大话设计模式用了聚合关系,我觉得具体可以随语境的不同而不同,也有可能是关联),Strategy类作为Context类的字段存在;然后在ContextInterface()方法中就可以决定要使用的具体算法了。代码为:
//抽象算法类
abstract class Strategy
{
public abstract void AlgorithmInterface(); //算法实现方法,被子类重写
}
//算法A
class ConcreteStrategyA: Strategy
{
public override void AlgorithmInterface()
{
//算法A具体实现
}
}
//算法B
class ConcreteStrategyB: Strategy
{
public override void AlgorithmInterface()
{
//算法B具体实现
}
}
//算法调用
class Context
{
Strategy strategy;
public Context(Strategy strategy) //就是在这儿决定具体算法的
{
this.strategy=strategy;
}
public void ContextInterface
{
strategy.AlgorithmInterface();
}
}
策略模式很好地实践了“针对接口编程,而不是针对实现编程”的原则,上文的抽象类Strategy就是一种“接口”或“超类型”,具体的算法子类都继承并重写了其中的主要方法,使用这种结构,可以保证每种算法都有统一的调用方式,这样在需要调用一种算法的时候,只需要调用算法族的父类,并利用“多态”,让父类指向某个具体算法类的引用。
这种方法可以在运行时方便地更换算法类;但如果要添加新的算法,除了编写新算法的类,还要在初始化Context类的地方做修改。对于这种不完美,据说仍有其它设计模式可以解决。拭目以待吧。
看了《Head First设计模式》的例子,关于一个动作冒险游戏,有Queen、King、Troll(是坑货的意思哈哈)等角色,角色的战斗方法有使用剑(Sword)、使用弓箭(BowAndArrow)等,那么角色更换装备的时候就可以用到策略模式了。受此启发,又想起了以前为之痴狂的日系Act神作《鬼泣3》,以前沉迷于其迷人的剧情、酣畅淋漓的战斗,而现在也可以模拟一下具体实现了。主角Dante可以变换自己的战斗风格和武器,风格有骗术师、枪神、剑圣、皇家护卫等,武器则有大剑、双刀、三节棍、拳套等等等,UML如下: