我的应用程序中有两层验证。首先是由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不会非常有用,因为我必须为不同的操作(例如删除和更新)为一个实体制作不同的验证。
所以我正在寻找一种更聪明的方法(模式可能),如果有人能给我一个提示,我将非常感激。
提前感谢!
答案 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;你的代码中的东西。每个策略类现在负责一种且仅一种类型的卡验证。 如果您寻求灵活且易于维护的代码结构 - 请使用策略设计模式。