重复权限校验逻辑违反DRY原则的适用设计模式咨询
问题对应解决方案
这个场景最匹配的实现思路是用装饰器模式剥离横切的权限逻辑,Web服务场景下可以直接用框架自带的拦截器/中间件能力落地,不需要在每个业务函数里重复写校验代码,完全符合DRY原则。
现有实现的问题
你当前分层里虽然把CanUserCreateOrModify抽成了独立函数,但本质还是要在每个业务入口手动调用这个函数,只要新增客户相关的操作(比如批量导出、客户分配),就要重复写一遍调用逻辑,后续权限规则调整(比如新增数据范围校验),要逐个修改所有调用点,很容易出现遗漏。
具体实现方式
- 核心原则:把权限校验这类和核心业务无关的通用逻辑完全抽离,不让业务函数感知权限逻辑的存在,执行时自动先跑校验、校验通过再进业务代码。
- 通用装饰器实现参考(伪代码,不绑定特定语言):
// 核心业务函数,只保留纯业务逻辑,完全不掺杂权限相关代码 function AddCustomer(req) { /* 执行客户新增的纯业务逻辑 */ } function EditCustomer(req) { /* 执行客户编辑的纯业务逻辑 */ } function DeleteCustomer(req) { /* 执行客户删除的纯业务逻辑 */ } // 通用权限装饰器,校验逻辑只需要写一次 function NeedPermission(requiredPermission, businessFunc) { return function wrappedFunc(req) { // 统一权限校验,所有需要权限控制的接口都复用这段逻辑 if (!checkUserPermission(req.currentUser, requiredPermission)) { throw new NoPermissionError("无对应操作权限") } // 校验通过后才执行真实业务逻辑 return businessFunc(req) } } // 接口组装/路由注册阶段统一绑定权限,业务代码零侵入 const addCustomerApi = NeedPermission("customer:create", AddCustomer) const editCustomerApi = NeedPermission("customer:edit", EditCustomer) const deleteCustomerApi = NeedPermission("customer:delete", DeleteCustomer)
- 框架简化方案:如果是常规Web MVC项目,直接用框架自带的过滤器、注解、中间件能力即可,比如C#的
[Authorize]特性、Java Spring的@PreAuthorize注解、Python FastAPI的依赖注入,本质都是这套思路,只需要给接口方法加对应的权限标记,框架会自动在请求进入业务逻辑前完成校验,连手动包装函数的步骤都可以省略。
落地注意事项
不要为了套用设计模式过度设计:如果你的项目确定后续不会新增更多客户相关操作,也不会调整权限规则,直接抽一个公共校验函数在三个方法开头调用也完全可以接受。设计模式是用来降低长期维护成本的工具,不是所有场景都必须上的硬性要求。
内容的提问来源于stack exchange,提问作者Trond
相关产品推荐
相关产品推荐

