【问题标题】:Data validation and account creation with Either - how to write it better?使用 Either 进行数据验证和帐户创建 - 如何更好地编写它?
【发布时间】:2021-12-14 12:13:48
【问题描述】:

我有一个带有创建方法的 AccountCreator 类,该方法采用 DTO 和创建帐户所需的数据。一开始尝试创建 2 个值对象(用户名和密码),然后验证用户名的唯一性,在构造函数中创建使用这 2 个值对象的 Account 实体并将其保存在 repo 中。当然,可能会返回密码长度错误等错误。我为此使用了 Eithers,现在的问题是这段代码是否可以,或者它可以以某种方式更好地编写?

public Either<Error, AccountDto> create(AccountCreateDto accountCreateDto) {

    var errorType = ErrorType.ACCOUNT_PERSISTENCE_ERROR;
    var errorMessage = "Not unique user name: " + accountCreateDto.userName;
    var error = new Error(errorType, errorMessage);

    return UserName
        .create(accountCreateDto.userName)
        .flatMap(userName ->
            userNameUniquenessChecker.isUnique(userName.text) ?
                Password
                    .create(accountCreateDto.password)
                    .flatMap(password -> {
                        var createdAccount = new Account(
                            userName,
                            password,
                            AccountStatus.OPEN,
                            LocalDateTime.now(),
                            new ArrayList<>()
                        );
                        var addedAccount = accountRepository.add(createdAccount);
                        var accountDto = new AccountDto(
                            addedAccount.userName.text,
                            addedAccount.password.text,
                            addedAccount.status,
                            addedAccount.creationDate,
                            (long) addedAccount.tasks.size()
                        );
                        return Either.right(accountDto);
                    }) : Either.left(error));
}

【问题讨论】:

    标签: java functional-programming either vavr


    【解决方案1】:

    习惯的 FP 方法是使用 Validation 风格的应用函子 - 在 Vavr 中有一个称为 Validation。您可以使用Validation.combine 将多个验证值合二为一,例如:

    public Validation<Seq<<Error>, AccountDto> create(AccountCreateDto accountCreateDto) {
        Validation<Seq<<Error>, Account> validAcc =
                Validation.combine(
                        UserName.create(accountCreateDto.userName),
                        Password.create(accountCreateDto.password)
                ).ap((un, pw) -> new Account(
                        un,
                        pw,
                        AccountStatus.OPEN,
                        LocalDateTime.now()
                );
    
        Validation<Seq<<Error>, Account> validAcc2 =
                validAcc.flatMap(acc -> validateUserIdIsUnique(acc));
                
        Validation<<Seq<Error>, AccountDto> validAccDto =
                validAcc2.map(accountRepository::add)
                        .map(addedAccount -> 
                                new AccountDto(
                                        addedAccount.userName.text,
                                        addedAccount.password.text,
                                        addedAccount.status,
                                        addedAccount.creationDate,
                                        (long) addedAccount.tasks.size()
                                )
                        );
    
        }
    
        return validAccDto;
    }
    
    private static final var errorType = ErrorType.ACCOUNT_PERSISTENCE_ERROR;
    private static final var errorMessage = "Not unique user name: " + accountCreateDto.userName;
    private static final var error = new Error(errorType, errorMessage);
    
    Validation<Seq<Error>, Account> validateUserIdIsUnique(Account acc) {
        return userNameUniquenessChecker.isUnique(acc.userName.text) ?
                Validation.valid(userName) :
                Validation.invalid(error);
    }
    

    您可以省略临时变量 - validAcc、validAcc2 和 validAccDto,但为了清楚起见,我将它们保留了。

    (警告购买者 - 尚未测试此代码是否有效,甚至无法编译)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-10
      • 2017-07-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多