You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Either实现数据校验与账号创建,如何优化现有代码写法?

现有代码合理性评估

现有代码的核心思路是合理的,用Either承载错误/正常返回结果,避免了传统异常流跳转的不可控问题,同时把用户名、密码的校验逻辑内聚在值对象的create方法中,符合DDD的设计原则,只是在结构设计、资源利用、可读性上还有优化空间。
存在的可优化点包括:

  • 错误对象提前实例化,且错误类型不匹配:用户名重复场景使用ACCOUNT_PERSISTENCE_ERROR不合理,且错误对象只有校验不通过时才会用到,提前创建属于无效资源消耗
  • 校验顺序不合理:密码合法性校验放在用户名唯一性校验之后,一旦密码不合法,之前的唯一性查库操作完全浪费
  • 嵌套层级过深:多层flatMap嵌套再叠加三元表达式,后续如果加更多校验逻辑,可读性会快速下降
  • 逻辑内聚性不足:Account的默认状态、创建时间、初始任务列表这些固定初始化逻辑放在服务层,后续修改Account默认规则需要同步改服务层代码
  • 重复逻辑未抽离:实体转Dto的映射逻辑写死在方法中,其他需要转AccountDto的场景还要重复写映射代码
优化后实现方案
public Either<Error, AccountDto> create(AccountCreateDto accountCreateDto) {
    // 先做无IO的值对象校验,避免无效查库
    return UserName.create(accountCreateDto.userName())
            // 合并两个值对象的校验结果
            .flatMap(userName -> Password.create(accountCreateDto.password())
                    .map(password -> new Tuple2<>(userName, password))
            )
            // 所有参数合法再执行需要查库的唯一性校验
            .flatMap(tuple -> {
                UserName userName = tuple._1;
                Password password = tuple._2;
                if (!userNameUniquenessChecker.isUnique(userName.text())) {
                    // 用到时再实例化错误,错误类型更精准
                    return Either.left(new Error(ErrorType.USER_NAME_DUPLICATED, 
                        "用户名不唯一: " + userName.text()));
                }
                // Account初始化逻辑内聚到自身静态工厂方法
                Account newAccount = Account.create(userName, password);
                Account savedAccount = accountRepository.add(newAccount);
                // 转换逻辑抽成Dto静态方法复用
                return Either.right(AccountDto.fromEntity(savedAccount));
            });
}

补充说明:

上面代码用到的Tuple可以用自定义的二元组类,也可以根据你所用的Either工具库的配套容器替换;Account的静态create方法内封装默认状态赋值、创建时间生成、空任务列表初始化逻辑,AccountDto的fromEntity方法封装实体到Dto的字段映射逻辑即可。

额外优化建议
  • 拆分错误枚举:为不同错误场景定义独立的枚举值,比如USER_NAME_INVALID、PASSWORD_INVALID、USER_NAME_DUPLICATED、ACCOUNT_SAVE_ERROR,后续排查问题、给前端返回错误码都更清晰
  • 可扩展校验逻辑:如果后续要加手机号校验、邮箱校验等逻辑,只需要在值对象校验阶段按同样逻辑追加即可,不会导致嵌套层级持续升高
  • 存储层错误兼容:当前代码没有处理repository.add的异常,建议把存储层的操作也封装成Either返回,把存储层错误也纳入统一的错误处理链路中

内容的提问来源于stack exchange,提问作者Sampeteq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 06:06:02