本文原创地址:jsbintask的博客(食用效果最佳),转载请注明出处!
前言
策略模式是一种行为模式,它用以运行时动态的改变类的行为,通过将一系列类似的算法封装成不同的类来达到目的,可以有效减少代码中if else的冗余。它实现的关键是面向接口接口编程以及有一个算法切换者。它的优点是扩展性良好,可以自由切换策略。
栗子
周末天气不错,小明准备去爬武功山,于是他请教它的出行助手应该选择怎样的工具去目的地才能让他最大化周末的快乐。于是它的出行助手开始了一段计算,操作。。。最终。。。
抽象
针对上面的案例,重点在于出行助手如何帮小明选择出行工具,这恰好可以对应我们一开始说的需要封装的算法,并且能够随意切换,于是我们可以得出下面的uml类图:
小明通过使用出行助手来选择不同的交通工具。而出行助手内部则通过代理
TravelStrategy
接口来切换不同的出行算法。
实现
首先定义出行接口TravelStrategy
:
@FunctionalInterface
public interface TravelStrategy {
void travel();
}
接着实现不同的出行算法,此处有BikeTravelStrategy
, FootTravelStrategy
, CarTravelStrategy
。
@Slf4j
public class BikeTravelStrategy implements TravelStrategy {
@Override
public void travel() {
log.info("自行车骑行半小时,行程18公里,感觉卡路里在燃烧!");
}
}
============================================================
@Slf4j
public class FootTravelStrategy implements TravelStrategy {
@Override
public void travel() {
log.info("徒步旅行半小时,行走5公里,可以好好欣赏周边景色");
}
}
============================================================
@Slf4j
public class CarTravelStrategy implements TravelStrategy {
@Override
public void travel() {
log.info("自驾旅行半小时,行程40公里,感觉时间走的真慢。");
}
}
接着就需要实现出行助手类:TravelService
,它内部通过代理TravelStategy
来切换不同的策略:
public class TravelService {
private TravelStrategy travelStrategy;
public void chooseTravelStrategy(TravelStrategy travelStrategy) {
this.travelStrategy = travelStrategy;
}
public void doTravel() {
this.travelStrategy.travel();
}
}
最后,编写一个测试类:
@Slf4j
public class App {
public static void main(String[] args) {
System.out.println("天气不错,小明准备出门旅行,它带上了它的旅行助手'TravelService'来帮它制定出行策略.");
TravelService travelService = new TravelService();
System.out.println("'TravelService': 天气不错,您可以选择徒步出行");
travelService.chooseTravelStrategy(new FootTravelStrategy());
travelService.doTravel();
System.out.println("'TravelService': 2小时后可能转小雨,建议您选择自行车加快形成,锻炼身体!");
travelService.chooseTravelStrategy(new BikeTravelStrategy());
travelService.doTravel();
System.out.println("'TravelService': 半小时后会有暴雨,建议您选择自驾汽车去目的地.");
travelService.chooseTravelStrategy(new CarTravelStrategy());
travelService.doTravel();
System.out.println("'TravelService': 天气已经好转,您可以随意选择出行方式。");
travelService.chooseTravelStrategy(() -> {
log.info("骑行摩托车开始,半小时形成30公里。刺激!");
});
System.out.println("'TravelService': 您已到达目的地.");
}
}
注意上面的关键代码为TravelService
根据不同的天气选择了不同的出行策略。
根据结果我们可以知道我们切换了三次不同的策略,并且使用lambda表达式添加了一个匿名策略。
总结
使用策略模式的关键在于面向接口编程,并且有一个全局切换策略的辅助类,它的优点在于扩展性良好,算法可以自由切换动态改变类的行为。
而它的缺点也很明显:策略类过多会导致“类爆炸“,并且所有的策略类都需要向外暴露。 所以使用时如果策略过多可以考虑使用混合模式,配合其它模式一起使用。
关注我,这里只有干货!