业务逻辑验证模式和建议

21

我的应用程序有两层验证。第一层是由Bean Validation API执行的实体验证(例如,必填字段)。第二层是业务逻辑验证。例如,用户有一篇帖子。只有当用户是该帖子的创建者且该帖子评级<50时,用户才能删除帖子。因此,我需要像这样做:

if (post.getCreator().equals(session.getUser())) {
  if (post.getRating() < 50) {
    postRepository.delete(post);
  } else errors.add(400, "Cant delete post with rating 50 or higher")
} else errors add (400, "You should be owner of the post")

我不喜欢这种方式,因为这些条件被重复使用,我需要复制代码。此外,如果条件数量大于5个左右,那么阅读和理解代码就变得不切实际。

此外,标准的Spring验证器在我需要对同一实体进行不同操作(例如删除和更新)的不同验证时并不是很有帮助。

因此,我正在寻找一种更智能的方法(可能是模式),如果有人能给我一些提示,我会非常感激。

提前感谢!

2个回答

29
你可以使用策略模式。每个条件都可以建模为一个函数,该函数接受一个帖子和一个会话上下文,并可能返回错误:
Post -> Session -> Optional<String> 

你可以用一个接口来表示它:

@FunctionalInterface
public interface ValidationCondition {

    Optional<String> validate(final Post post, final Session session);
}

所以举个例子:

public class CreatorValidation implements ValidationCondition {
    
    public Optional<String> validate(final Post post, final Session session) {
        if (post.getCreator().equals(session.getUser()) {
            return Optional.empty();
        }
        return Optional.of("You should be the owner of the post");
    }
}

您可以将每个验证结果存储在列表中:

final List<ValidationCondition> conditions = new ArrayList<>();

conditions.add(new CreatorValidation());
conditions.add(new ScoreValidation());
// etc.

使用列表,可以批量应用验证:

final List<String> errors = new ArrayList<>();

for (final ValidationCondition condition : conditions) {
    final Optional<String> error = condition.validate(post, session);
    if (error.isPresent()) {
        errors.add(error.get());
    }
}

使用 Java 8 的 lambda 表达式,你可以内联声明这些:

final ValidationCondition condition = (post, session) -> {
    // Custom logic
});

3

在我看来,策略模式是解决方案。我将给你一个非常简单的例子。假设我们有两种信用卡,Visa和Mastercard。执行付款操作的逻辑对于两种卡片是相同的,但卡号验证不同。因此,通过将VisaStrategy对象通过工作流程传递,与我们传递MastercardStrategy一样执行相同的逻辑和操作,除了一件事 - 卡号验证,这是在每个定义的策略类内完成的,因此您在代码中没有任何“if else”内容。现在,每个策略类负责一种且仅一种类型的卡验证。如果您寻找灵活且易于维护的代码结构-请使用策略设计模式。


3
如果验证方法的参数因条件而异怎么办?比如说,Visa信用卡号是一个整数且有一个四位数的代码,但Master信用卡号是16位数字? - ahmet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接