【问题标题】:Business logic validation patterns & advices业务逻辑验证模式和建议
【发布时间】:2016-07-04 12:12:19
【问题描述】:

我的应用程序中有两层验证。首先是由 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 不会很有帮助,因为我必须针对不同的操作(例如删除和更新)对一个实体进行不同的验证

所以我正在寻找一种以更智能的方式(可能是模式)执行此操作的方法,如果有人能给我提示,我将不胜感激。

提前致谢!

【问题讨论】:

    标签: java spring validation design-patterns


    【解决方案1】:

    您可以使用the strategy pattern

    每个条件都可以建模为一个接受帖子和会话上下文并可能返回错误的函数:

    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
    });
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 如果验证方法的参数因条件而异怎么办?假设 Visa 卡号是一个整数,也有一个 4 位代码,但主卡号是一个 16 位数字?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-20
      • 2010-10-12
      • 1970-01-01
      • 2011-12-22
      • 2011-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多