业务逻辑验证模式&建议

时间:2016-07-04 12:12:20

标签: java spring validation design-patterns

我的应用程序中有两层验证。首先是由bean验证API执行的实体验证(例如必填字段)。 第二级是业务逻辑验证。例如,用户有一个帖子。用户只有在他是该帖子的创建者并且发布评级<所以我必须做这样的事情:

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 Validator不会非常有用,因为我必须为不同的操作(例如删除和更新)为一个实体制作不同的验证。

所以我正在寻找一种更聪明的方法(模式可能),如果有人能给我一个提示,我将非常感激。

提前感谢!

2 个答案:

答案 0 :(得分:11)

您可以使用the strategy pattern

每个条件都可以建模为一个接收帖子和会话的函数,可能会返回错误:

Post -> PostContext -> 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 lambdas,您可以声明这些内联:

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

答案 1 :(得分:2)

战略模式是我认为的解决方案。 我会举一个非常简单的例子。可以说我们有两种信用卡,Visa和万事达卡。执行付款操作的逻辑对于两张卡都是相同的,但卡号验证是不同的。所以,通过工作流程传递VisaStrategy对象,我们会传递与MastercardStrategy相同的逻辑和操作,除了一件事 - 卡号验证,这是在每个定义的策略类中完成的,所以你没有任何&#34; if else& #34;你的代码中的东西。每个策略类现在负责一种且仅一种类型的卡验证。 如果您寻求灵活且易于维护的代码结构 - 请使用策略设计模式。