策略模式
策略模式:策略模式是一种行为型设计模式,它允许在运行时选择算法的行为。通过将算法封装成独立的类,客户端代码可以方便地更换算法实现,而无需修改其余代码。
在策略模式中,算法被定义为一组接口,并且每个算法都有自己的实现类。这些算法实现类通常共享一个公共接口,使得它们可以互换使用。在运行时,客户端可以根据需要选择其中一种算法实现,并将其传递给上下文对象,以便使用该算法执行特定的行为。用图表示如下:
策略模式的优点:
算法可以在运行时进行更换,而无需修改客户端代码。
算法可以被封装成独立的类,使得代码更易于维护和测试。
可以通过定义新的算法实现类来扩展应用程序的功能,而无需修改现有代码。
算法实现类可以被多个客户端对象共享,提高了代码的复用性。
策略模式的缺点:
需要客户端代码来选择正确的算法实现,增加了一定的复杂性。
如果有大量的算法实现类,则可能会导致类层次结构过于复杂。
使用策略模式可能会导致客户端代码变得过于分散,需要谨慎设计。
策略模式的主要角色如下。
抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
环境(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;
}