策略,指计策或谋略,是可以实现目标的方案集合。在我们日常生活中其实这种问题也比较常见,比如我们使用地图搜索目的地,在地图上给我们提供了多种路线方案供我们选择。这里的路线方案其实就是我们的策略,每一个方案的实现是一个算法,具体用哪个路线方案,需要根据实际情况和用户的选择来确定。
前面我们说到模板方法,它是基于继承的,它允许您通过在子类中扩展这些部分来更改算法的部分。而策略模式则是基于组合的,可以通过为对象提供与该行为相对应的不同策略来改变对象行为的一部分。模板方法是在类级别上的运用,是静态的,而策略模式是在对象级别起作用,让您在运行时切换行为。
定义
策略模式是一种行为设计模式,它允许您定义一系列算法,并将每个算法提取到称为策略的单独类中,由客户端选择调用,使它们可以相互替换,且算法的变化不会影响使用算法的客户。
策略模式的结构:
1)抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口;
2)具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现;
3)环境(Context)类:持有一个策略类的引用,最终给客户端调用。
策略模式的意图在于:分离算法,选择实现。即把可互换的方法封装在各自独立的类中,方便更换算法或增加新的算法。
优点
1)将算法的实现细节和客户端隔离,可以在运行时根据实际情况选择不同的算法;
2)符合开闭原则,可以在不修改原代码的情况下,灵活增加新算法。
缺点
1)客户端必须了解策略之间的差异才能选择合适的策略;
2)可以借助匿名类/函数中实现不同的算法,也不必额外的添加其他的类或接口使代码变得臃肿。
以去公园为例,可以有很多路线方式去公园。
1)抽象策略类
- //抽象策略(Strategy)类
- public interface Strategy {
-
- void goToPark(); //去公园
- }
2)具体策略类
- //具体策略(Concrete Strategy)类
- public class BySubwayStrategy implements Strategy{
-
- @Override
- public void goToPark() {
- System.out.println("乘地铁去公园");
- }
-
- }
-
- //具体策略(Concrete Strategy)类
- public class ByBusStrategy implements Strategy{
-
- @Override
- public void goToPark() {
- System.out.println("乘公交去公园");
- }
-
- }
-
- //具体策略(Concrete Strategy)类
- public class ByTaxiStrategy implements Strategy{
-
- @Override
- public void goToPark() {
- System.out.println("打车去公园");
- }
-
- }
3)环境类
- //负责和具体的策略类交互,使得算法和客户端分离
- public class Context {
- private Strategy strategy; //当前采用的具体对象,即具体的算法对象
-
- //支持使用构造注入
- public Context(Strategy strategy){
- this.strategy = strategy;
- }
-
- //也可以通过set注入
- public void setStrategy(Strategy strategy){
- this.strategy = strategy;
- }
-
- public void goToPark(){
- this.strategy.goToPark();
- }
-
- }
4)客户端
- public class Client {
-
- public static void main(String[] args) {
- Strategy bySubway = new BySubwayStrategy();
- //乘地铁
- Context ctx = new Context(bySubway);
- ctx.goToPark();
- //乘公交
- Strategy byBus = new ByBusStrategy();
- ctx.setStrategy(byBus);
- ctx.goToPark();
- //打车
- Strategy byTaxi = new ByTaxiStrategy();
- ctx.setStrategy(byTaxi);
- ctx.goToPark();
- }
- }
此时的UML图:
策略模式在 Java 代码中非常常见。它经常在各种框架中使用,为用户提供一种无需扩展类即可更改类行为的方法,它通常描述的是做同一件事的不同方式,让你在单个上下文类中交换这些算法。
这种写法跟我们在装饰器模式中的写法有点像,但是装饰器更像是对外表的一种装饰,而策略模式是彻底的内在的改变。
应用场景:
1)当有许多相似的类,它们只是在执行某些行为的方式上有所不同时,请使用策略模式;
2)当有大量条件语句在同一算法的不同变体之间切换时,可将每个条件分支移入它们各自的策略类中替代这些条件语句,来消除这种条件。
JDK中策略模式的应用:
java.util.Comparator#compare()调用Collections#sort()
javax.servlet.http.HttpServlet:service()方法
javax.servlet.Filter#doFilter()