相信大部分开发者都见过这样的代码:
@Component class RequestReceiver {
public Response receiveRequest(Request request) { switch (request.getType()) { case GET: return handleGet(request); case POST: return handlePost(request); case PUT: return handlePut(request); default: throw new IllegalArgumentException("Unknown request type: " + request.getType()); } } }
|
乍一看,这个实现没有任何问题,看起来很干净。
但是,假设我们要添加对 DELETE、PATCH 和 HEAD HTTP 方法的支持。为此,我们需要为此类中的每个方法实现处理逻辑,并将它们包含在 switch 块中。这完全违反了开闭原则,该原则指出:软件实体应该对扩展开放,但对修改关闭。根据我自己的经验,我看到过一些长达数百行的 switch 语句,我向您保证,这样的代码很混乱且难以测试。如果我们可以在不触及现有逻辑的情况下添加对新 HTTP 方法的支持,那就太好了。这就是策略设计模式可以帮助我们的地方。
策略模式是一种行为软件设计模式,可以在运行时选择算法。代码不是直接实现单个算法,而是接收关于在一系列算法中使用哪个的运行时指令。
让我们尝试应用此模式并重新实现我们的RequestReceiver 类。首先,我们需要定义一个新的抽象,负责处理单个请求。
interface RequestHandler { Response handle(Request request);
RequestType supportedRequestType(); }
@Component class GetRequestHandler implements RequestHandler {
@Override public Response handle(Request request) {...}
@Override public RequestType supportedRequestType() { return RequestType.GET; } }
@Component class PostRequestHandler implements RequestHandler {
@Override public Response handle(Request request) {...}
@Override public RequestType supportedRequestType() { return RequestType.POST; } }
@Component class PutRequestHandler implements RequestHandler {
@Override public Response handle(Request request) {...}
@Override public RequestType supportedRequestType() { return RequestType.PUT; } }
|
创建新的抽象后,有几种方法可以使用它们,我将展示其中的几种:
1. 使用 Map 实现 @RequiredArgsConstructor class RequestReceiver {
private final Map<RequestType, RequestHandler> requestHandlers;
public Response receiveRequest(Request request) { if (!requestHandlers.containsKey(request.getType())) { throw new IllegalArgumentException("Unknown request type: " + request.getType()); } return requestHandlers.get(request.getType()).handle(request); } }
|
我们需要用策略填充我们的Map,为此,我们创建了一个配置类。@Configuration class RequestReceiverConfiguration {
@Bean public RequestReceiver requestReceiver(List<RequestHandler> requestHandlers) { return new RequestReceiver( requestHandlers.stream() .collect(toMap(RequestHandler::supportedRequestType, Function.identity())) ); } }
|
2. 使用专用注册表实现
让我们为RequestHandlers实现一个注册表:
@Component @RequiredArgsConstructor class RequestHandlerRegistry {
private final List<RequestHandler> requestHandlers;
public Optional<RequestHandler> getHandlerFor(Request request) { return requestHandlers.stream() .filter(handler -> handler.supportedRequestType().equals(request.getType())) .findAny(); } }
|
RequestReceiver 的最终实现:
@Component @RequiredArgsConstructor class RequestReceiver {
private final RequestHandlerRegistry registry;
public Response receiveRequest(Request request) { return registry.getHandlerFor(request) .orElseThrow(() -> new IllegalArgumentException("Unknown request type: " + request.getType())) .handle(request); } }
|
重构后,这两种方法都使我们的设计隔离,同时对扩展开放,现在我们可以轻松地为 DELETE 方法添加新的实现,而无需更改一行现有代码:
@Component class DeleteRequestHandler implements RequestHandler {
@Override public Response handle(Request request) {}
@Override public RequestType supportedRequestType() { return RequestType.DELETE; } }
|
结论
在本文中,我们解释了策略模式,并演示了如何在 Spring Boot 应用程序中实现它。