策略模式的思想是提取算法或者行为,对算法或者策略进行封装成类,并装配到一个环境类(context)上,使得环境类可以使用不同的算法或者策略来解决不同的问题。策略模式是一种行为型设计模式。
这种设计模式解决的是硬编码场景中的算法扩展问题。针对某一个场景,可能存在多个算法来进行处理。这多个算法,可能是写在一个工具类的不同的方法中,也有可能是写在一个方法中根据不同的条件进行if-else的选择。但是这样的处理方式的扩展性非常差劲,如果要增加一种算法,就需要修改工具类。要增加代码的扩展性,就需要为每个算法新建一个类,其中放置算法逻辑。这样当新增算法的时候,只需要增加对应的算法类即可,这就是策略模式的主要内容。
实现:策略模式中一般存在如下几个角色:
- 抽象策略接口:定义策略类的通用接口,是策略或者算法的调用入口。
- 具体策略类:策略实现类,根据业务场景包含某一种算法的真实执行逻辑。具体策略类用于装配环境类,从而让环境类能够有能力进行不同的处理逻辑。
- 环境类(context):依赖抽象策略接口,使用具体策略类装备自己。客户端根据具体场景,选择对应的具体策略类来装配环境类,为环境类赋能。环境类只负责处理具体场景下的问题。具体策略类的选择是客户端进行的,环境类不提供该能力。
使用场景:系统中存在多种可供选择的策略或者算法,针对各种不同的场景,需要提取出一种算法或者策略进行处理的时候,可以选择策略模式。
- 比如某些银行卡会推出普通会员卡,银卡,金卡和钻石卡。每种银行卡在购物时候享受的优惠是不同的,在计算优惠的时候,就存在了不同的策略和算法,比如会员卡9折,银卡8折,金卡7折和钻石卡6折,这样就存在了4中算法。当购物的时候,需要顾客的会员卡等级,选择出对应的策略来进行总价计算。
- 比如出去玩,可以步行,骑自行车,开车,打车。那么就需要从这么多的策略中选出一种来。比如为了锻炼身体,选择了步行。但是某人提出要赶时间,那就改为用打车的策略来装配决策类,改为打车的方式出行。
案例
背景
以假期出行为例,总是存在多种出行策略的选择。去浪漫的土耳其,去东京和巴黎,还特别喜欢迈阿密,有黑人的洛杉矶。假期有限,只能选择其中的一种。那么就跟小伙伴开始商量(context类),小伙伴A说土耳其比较便宜,毕竟经费有限。OK,那就决定去土耳其了。然后小伙伴B说,他家里有亲戚在东京,包吃包住。OK,那就取东京把。最后小伙伴C说了,他想去迈阿密,让大家跟他一起,所有经费他包了。OK,那就去迈阿密把。
实现
抽象策略接口
public interface Strategy
{
void go();
}
具体策略类
public class TurkeyVocation implements Strategy
{
@Override
public void go()
{
System.out.println("去土耳其。");
}
}
public class TokyoVocation implements Strategy
{
@Override
public void go()
{
System.out.println("去东京。");
}
}
public class MiamiVocation implements Strategy
{
@Override
public void go()
{
System.out.println("去迈阿密拉。");
}
}
环境类
public class Context
{
private Strategy strategy;
public Context(Strategy strategy)
{
this.strategy = strategy;
}
public void setStrategy(Strategy strategy)
{
this.strategy = strategy;
}
public void action()
{
this.strategy.go();
}
}
验证程序
/**
* 验证
*/
public class Demo
{
public static void main(String[] args)
{
System.out.println("小伙伴A:土耳其比较便宜,毕竟经费有限");
Strategy strategy = new TurkeyVocation();
Context context = new Context(strategy);
context.action();
System.out.println("小伙伴B:家里有亲戚在东京,包吃包住");
strategy = new TokyoVocation();
context.setStrategy(strategy);
context.action();
System.out.println("小伙伴C:所有经费我包了");
strategy = new MiamiVocation();
context.setStrategy(strategy);
context.action();
}
}
运行结果
总结小伙伴A:土耳其比较便宜,毕竟经费有限
去土耳其。
小伙伴B:家里有亲戚在东京,包吃包住
去东京。
小伙伴C:所有经费我包了
去迈阿密拉。Process finished with exit code 0
核心思想就是将算法或者策略封装成类。
优点:各种算法可以自由切换,具有非常好的扩展性。
缺点:每一种策略都需要封装成一个类,可能会存在较多的策略类。