策略模式(Strategy):定义了算法家族,将不同的算法分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
一、策略模式
策略模式的背景:
在软件开发中常常遇到这种情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能。如查找、排序等,一种常用的方法是硬编码(Hard Coding)。在一个类中,如需要提供多种查找算法,可以将这些算法写到一个类中,在该类中提供多个方法,每一个方法对应一个具体的查找算法;当然也可以将这些查找算法封装在一个统一的方法中,通过if…else…或者case等条件判断语句来进行选择。
如果需要增加一种新的算法,需要修改封装算法类的源代码;更换算法,也需要修改客户端调用代码。在这个算法类中封装了大量算法,该类代码将较复杂,维护较为困难。如果我们将这些策略包含在客户端,这种做法更不可取,将导致客户端程序庞大而且难以维护,如果存在大量可供选择的算法时问题将变得更加严重。
把一个类中经常改变或者将来可能改变的部分提取出来,作为一个接口,然后在类中包含这个对象的实例,这样类的实例在运行时就可以随意调用实现了这个接口的类的行为。
策略模式的UML图如下:
策略模式由以下部分组成:
环境(Context)角色:持有一个Strategy的引用。
抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
二、案例分析:
我们借用西游记的故事,来简单学习一下策略模式:
在西游记第七十九回《寻洞擒妖逢老寿,当朝正主救婴儿》中,师徒四人来到比丘国境界,国王听信妖怪,要拿唐僧的心做药引子,于是孙悟空变成了唐僧的模样,在大殿之上,戏耍了众人一番:
昏君道:“特求长老的心肝。”
假唐僧道:“不瞒陛下说,心便有几个儿,不知要的甚么色样。”
那国丈在旁指定道:“那和尚,要你的黑心。”
……
假僧将那些心,血淋淋的,一个个捡开与众观看,却都是些红心、白心、黄心、悭贪心、利名心、嫉妒心、计较心、好胜心、望高心、侮慢心、杀害心、狠毒心、恐怖心、谨慎心、邪妄心、无名隐暗之心、种种不善之心,更无一个黑心 。
在这个案例中,孙悟空变出什么心,其实就是一种算法,算法本身就是一种策略,重要的是这些算法随时都可能互相替换,这就是变化点。其UML图如下:
代码部分:
Strategy 类(孙悟空)
abstract class Strategy{
public abstract void changeHeart();
}
ConcreteStrategy ,封装了具体的算法或行为。
class ConcreteStrategyA extends Strategy{
public void changeHeart(){
System.out.println("我是一颗红心");
}
}
class ConcreteStrategyB extends Strategy{
public void changeHeart(){
System.out.println("我是一颗计较心");
}
}
class ConcreteStrategyC extends Strategy{
public void changeHeart(){
System.out.println("我是一颗利名心");
}
}
......
Context (妖怪),用来对Strategy进行引用
class Monster{
Strategy strategy ;
public Monster(Strategy strategy ){
this.strategy = strategy;
}
public void GiveMeAHeart(){
strategy.changeHeart();
}
}
故事上演 :
public class Story{
public static void main(String[] args) {
Monster monster = new Monster(new ConcreteStrategyA ());
monster.GiveMeAHeart();
monster = new Monster(new ConcreteStrategyB());
monster.GiveMeAHeart();
monster = new Monster(new ConcreteStrategyC());
monster.GiveMeAHeart();
}
}
运行结果(代码亲测可以通过):
代码地址:Strategy
当妖怪要的黑心,孙悟空能够满足时,只要建立相对应的ConcreteStrategy就能提供了,满足了开闭原则,当然大圣是没有黑心的。
其实,看到这儿,大家可能会发现,上面的例子不就是一个接口和实现了该接口的若干类嘛,确实这个例子有待完善,因为策略模式更注重的是封装算法,,实际开发过程中,更多的应用在算法决策系统中,外部用户只需要决定用哪个算法即可。比如:超市打折促销,不同的优惠方法会有不同的算法。
欢迎大家留言评论,点击查看更多设计模式。