策略模式:策略模式是一种行为型设计模式,它允许在运行时选择算法的行为。通过将算法封装成独立的类,客户端代码可以方便地更换算法实现,而无需修改其余代码。

在策略模式中,算法被定义为一组接口,并且每个算法都有自己的实现类。这些算法实现类通常共享一个公共接口,使得它们可以互换使用。在运行时,客户端可以根据需要选择其中一种算法实现,并将其传递给上下文对象,以便使用该算法执行特定的行为。用图表示如下:

策略模式的优点:

  • 算法可以在运行时进行更换,而无需修改客户端代码。

  • 算法可以被封装成独立的类,使得代码更易于维护和测试。

  • 可以通过定义新的算法实现类来扩展应用程序的功能,而无需修改现有代码。

  • 算法实现类可以被多个客户端对象共享,提高了代码的复用性。

策略模式的缺点:

  • 需要客户端代码来选择正确的算法实现,增加了一定的复杂性。

  • 如果有大量的算法实现类,则可能会导致类层次结构过于复杂。

  • 使用策略模式可能会导致客户端代码变得过于分散,需要谨慎设计。

策略模式的主要角色如下。

  1. 抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。

  2. 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。

  3. 环境(Context)类:持有一个策略类的引用,最终给客户端调用。

策略模式的实现

// 抽象策略类
interface Strategy {
   public int doOperation(int num1, int num2);
}
// 具体策略类A
class OperationAdd implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 + num2;
   }
}
// 具体策略类B
class OperationSubtract implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 - num2;
   }
}
// 具体策略类C
class OperationMultiply implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 * num2;
   }
}
// 环境类
class Context {
   private Strategy strategy;
   
   public Context(Strategy strategy){
      this.strategy = strategy;
   }
   
   public int executeStrategy(int num1, int num2){
      return strategy.doOperation(num1, num2);
   }
}
// 测试类
public class StrategyPatternTest {
    public static void main(String[] args) {
      Context context = new Context(new OperationAdd());    
      System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
 
      context = new Context(new OperationSubtract());      
      System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
 
      context = new Context(new OperationMultiply());    
      System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
   }
}

程序运行结果如下:

10 + 5 = 15

10 - 5 = 5

10 * 5 = 50

策略模式在SpringMVC中的应用

SpringMVC中大量使用了策略模式,如

1.将请求参数中的数据解析成对象的HandlerMethodArgumentResolver

public interface HandlerMethodArgumentResolver {
    
    boolean supportsParameter(MethodParameter parameter);
    
    Object resolveArgument(MethodParameter parameter, 
            ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, 
            WebDataBinderFactory binderFactory) throws Exception;
  
}

在InvocableHandlerMethod#getMethodArgumentValues方法中,会遍历Spring容器中的HandlerMethodArgumentResolver的所有实现类,直到找到一个supportsParameter返回true的策略类,使用该策略类将请求参数解析成Java对象。

protected Object[] getMethodArgumentValues(NativeWebRequest request, 
            ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
    
       MethodParameter[] parameters = getMethodParameters();
       if (ObjectUtils.isEmpty(parameters)) {
          return EMPTY_ARGS;
       }
    
       Object[] args = new Object[parameters.length];
       for (int i = 0; i < parameters.length; i++) {
          MethodParameter parameter = parameters[i];
          parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
          // 如果 providedArgs 提供了参数值, 则直接进行使用
          args[i] = findProvidedArgument(parameter, providedArgs);
          if (args[i] != null) {
             continue;
          }
          // 如果所有resolver都无法适配, 则直接抛出异常
          if (!this.resolvers.supportsParameter(parameter)) {
             throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
          }
          try {
             // 使用具体的策略实现类来进行参数的解析
             args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
          }
          ……
       }
       return args;
}   

2.将响应对象转换为视图或Json等操作的HandlerMethodReturnValueHandler

public interface HandlerMethodReturnValueHandler {
    
    boolean supportsReturnType(MethodParameter returnType);
    
    void handleReturnValue(Object returnValue, 
            MethodParameter returnType,
            ModelAndViewContainer mavContainer, 
            NativeWebRequest webRequest) throws Exception;            
    
}

文章作者: Hakurei
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Zero
设计模式 设计模式 Java
喜欢就支持一下吧