Java EE Web方法需遵循内部方法调用序列,适用何种设计模式?
完全懂你的顾虑——把每个Web方法都塞进模板类里,感觉既笨重又和Web服务的调用模式有点脱节,毕竟这些方法是对外暴露的接口,不是普通的类方法。其实除了模板方法模式,还有几个更贴合Web场景的思路可以试试:
1. 拦截器/过滤器模式(Interceptor/Filter Pattern)
这应该是最适合Web服务场景的方案了。你可以把checkPermissions、validateInput这些通用逻辑做成独立的拦截器,然后配置到你的Web服务框架里,让每个Web方法在执行前自动经过这些拦截器的处理。
举个伪代码示例(以支持AOP的框架为例):
// 权限检查拦截器 public class PermissionCheckInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { var userId = invocation.Arguments[0]; // 假设第一个参数是用户标识 if (!HasOperationPermission(userId, invocation.Method.Name)) { throw new UnauthorizedAccessException("无此操作权限"); } invocation.Proceed(); // 继续执行下一个拦截器或目标业务方法 } } // 输入验证拦截器 public class InputValidationInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { var inputData = invocation.Arguments[1]; // 假设第二个参数是业务输入 if (!ValidateBookInput(inputData, invocation.Method.Name)) { throw new ArgumentException("输入参数不符合要求"); } invocation.Proceed(); } }
然后在Web服务的配置中,把这些拦截器绑定到createBook、readBook等目标方法上。这样每次外部调用Web方法时,框架会自动按你设定的顺序执行拦截器,最后才触发核心的业务逻辑(也就是你说的execute)。
优点:完全解耦通用逻辑和业务方法,每个拦截器只负责单一职责,后续调整流程顺序、新增检查步骤,只需要修改配置或新增拦截器,不用动业务代码。
2. 装饰器模式(Decorator Pattern)
如果你的Web服务框架不支持拦截器,也可以用装饰器来包裹每个Web方法。为核心业务类创建一个装饰器类,在装饰器里先执行权限检查、输入验证,再调用实际的业务方法。
伪代码示例:
public class BookServiceDecorator implements BookService { private final BookService targetService; public BookServiceDecorator(BookService targetService) { this.targetService = targetService; } @Override public Book createBook(User operator, BookCreateRequest request) { // 第一步:权限校验 if (!checkPermissions(operator, "createBook")) { throw new UnauthorizedException("无创建图书权限"); } // 第二步:输入验证 if (!validateCreateBookInput(request)) { throw new InvalidRequestException("创建参数格式错误"); } // 第三步:执行核心业务 return targetService.createBook(operator, request); } // readBook、editBook方法同理,按需调整校验逻辑 }
之后把装饰后的实例注册为Web服务的实现类,外部调用的就是装饰器的方法,自动走你设定的流程。
优点:比模板模式灵活,你可以给不同的Web方法配置不同的装饰器组合——比如readBook可能不需要复杂的输入验证,就可以简化装饰器逻辑。
3. 改进版模板方法模式
如果你还是想用模板模式,但觉得传统类实现太笨重,可以调整结构:把模板逻辑放到一个基础Web服务基类里,让你的图书服务类继承这个基类,只需要实现execute部分的业务逻辑。
伪代码示例:
class BaseWebService: def process_request(self, method_name, *args): # 固定流程第一步:权限检查 self._check_permissions(method_name, args[0]) # 固定流程第二步:输入验证 self._validate_input(method_name, args[1]) # 固定流程第三步:执行业务 return self._execute_business(method_name, *args) def _check_permissions(self, method_name, operator): # 通用权限检查逻辑,可根据method_name适配不同规则 pass def _validate_input(self, method_name, input_data): # 根据方法名调用对应验证逻辑 if method_name == "createBook": return self._validate_create_book_input(input_data) elif method_name == "editBook": return self._validate_edit_book_input(input_data) return True def _execute_business(self, method_name, *args): # 子类实现具体业务逻辑 raise NotImplementedError class BookService(BaseWebService): def _execute_business(self, method_name, *args): if method_name == "createBook": return self._inner_create_book(args[0], args[1]) elif method_name == "readBook": return self._inner_read_book(args[0], args[1]) # 其他方法实现... def _inner_create_book(self, operator, request): # 实际创建图书的业务逻辑 pass
然后你的Web方法只需要调用process_request,传入方法名和参数即可。这样既保留了模板模式的固定流程,又不用给每个Web方法单独写重复的模板代码,相对简洁很多。
总的来说,拦截器/过滤器模式是最贴合Web服务场景的,因为大多数主流Web服务框架(比如ASP.NET Web API、Spring MVC、FastAPI等)都原生支持这种扩展方式,配置起来也方便。如果框架不支持,装饰器模式是个不错的替代,而改进版的模板模式也能解决你觉得“笨重”的问题。
内容的提问来源于stack exchange,提问作者aerojas

