策略模式
定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换,让算法独立于使用它的客户而独立变化
本质:分离算法,选择实现。
看不懂这个神仙一般的定义没关系,老规矩,先搞个反面例子来引出我们的策略模式
在暑假的第一天,有几个选择摆在我面前,分别是打英雄联盟,做家务,睡觉,学习。显然每个行为都可以看成是一种行为策略,那么我到底会选择什么呢,这应该根据具体的情况来做出选择。
if(weather.equals("出太阳")){
//打 lol
}else if(weather.equals("阴天")){
//睡觉
}else if(weather.equals("下雨")){
//做家务
}else if(weather.equals("下雪")){
//学习
}
一般来说,我们会这样用编程语言来描述,但这样的话,存在一个问题,假如我想到一个新的选择的话,那么我就要在原来代码的基础上增加新的else if语句,显然这违背了我们的开发中的开放-封闭原则(具备可拓展性),所以我们要考虑下换种思路啦,我们不妨把定义一个策略接口,该接口中定义一个do方法,我们的每种行为策略都实现这个接口并实现接口中定义的方法。这样的话当我们需要增加新的策略的时候,就只需要增加一个接口实现类就ok啦,这就是我们的策略模式。
主要角色
- 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
- 具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
- 环境(Context)角色:持有一个Strategy的引用。
具体实现
首先定义个抽象策略角色
//策略接口
public interface Strategy {
void dothing();
}
再定义具体行为策略,实现策略接口
public class SunnyStrategy implements Strategy{
@Override
public void dothing() {
System.out.println("我要打撸啊撸,请不要阻止我");
}
}
public class CloudyStrategy implements Strategy{
@Override
public void dothing() {
System.out.println("我要睡觉zzz");
}
}
public class RainyStrategy implements Strategy{
@Override
public void dothing() {
System.out.println("我要做家务,哎");
}
}
public class SnowyStrategy implements Strategy{
@Override
public void dothing() {
System.out.println("我要学习,如果你打扰我,我就陪你玩");
}
}
接着定义一个持有一个Strategy引用的环境角色,用于执行具体的策略。
public class Context {
private Strategy strategy;
public Context(Strategy stratege) {
this.strategy = stratege;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void doOneThing(){
strategy.dothing();
}
}
客户端测试
public class Client {
public static void main(String[] args) {
Strategy sunnyday = new SunnyStrategy();
Context context = new Context(sunnyday);
context.doOneThing();
}
}
优点
- 策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
- 策略模式提供了可以替换继承关系的办法。
- 使用策略模式可以避免使用多重条件转移语句。
不足
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
- 策略模式将造成产生很多策略类,
适用场景
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 一个系统需要动态地在几种算法中选择一种。
- 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。