可返回对象全部校验失败原因的常用设计模式有哪些?
适用方案:通知(Notification)模式
该模式专门针对批量校验场景设计,核心逻辑是收集所有校验错误后统一返回,而非遇到第一个错误就中断执行,完全匹配你需要返回对象全部无效原因的需求,同时可以解决现有代码耦合度高、扩展性差的问题。
现有代码的核心问题
- 校验逻辑耦合在类构造函数中,新增校验规则、新增参数都需要修改构造函数的init代码块,违反开闭原则
- 用构造函数抛异常的方式处理预期内的参数校验问题,既增加了上层调用的try-catch负担,也不符合异常仅用于处理非预期错误的设计原则
- 错误信息存储格式灵活度低,后续要扩展结构化错误(比如错误码、关联字段)的成本很高
优化实现步骤
1. 定义基础结构
// 自定义异常兼容原有逻辑 class InvalidFooException(message: String): Exception(message)
2. 重构Foo类,用私有构造+工厂方法创建实例
将校验逻辑从构造函数抽离到工厂方法,保证只有校验通过的合法实例才会被创建,同时校验规则可独立配置,扩展性更强:
class Foo private constructor(val a: String, val b: String) { companion object { // 校验规则可独立配置,新增规则仅需要往列表中添加元素即可 private val validationRules = listOf<(String?, String?) -> String?>( { a, _ -> if (a == null) "a 不能为空" else null }, { _, b -> if (b == null) "b 不能为空" else null } ) fun create(a: String?, b: String?): Result<Foo> { val errors = validationRules.mapNotNull { rule -> rule(a, b) } return if (errors.isEmpty()) { Result.success(Foo(a, b)) } else { Result.failure(InvalidFooException(errors.joinToString(";"))) } } } }
3. 上层调用逻辑优化
不需要依赖try-catch处理校验结果,代码可读性更高:
fun parentMethod(a: String?, b: String?) { // 原有业务逻辑 Foo.create(a, b).fold( onSuccess = { foo -> // 处理合法的Foo实例 }, onFailure = { e -> LOG.info("创建Foo实例出错", e.message) // 此处可拿到全部错误信息 } ) }
进阶优化方向
- 校验规则泛化:如果多个业务类都需要类似校验,可以抽象通用的
ValidationRule接口,不同业务类的校验规则分别实现接口,运行时动态组装规则,完全解耦校验逻辑和业务类 - 错误结构化:把错误信息从纯字符串改成包含
错误字段、错误码、错误描述的结构化对象,方便上游系统做针对性提示、国际化适配等处理 - 复用框架能力:如果是Web接口的Payload校验场景,JSR-380(Bean Validation)规范以及Spring Validation等框架原生支持全量错误收集,无需自己手动实现规则逻辑
内容的提问来源于stack exchange,提问作者stk1234
相关产品推荐
相关产品推荐

