Java - 设计模式解决多个条件逻辑

时间:2017-01-11 21:52:11

标签: java design-patterns strategy-pattern

说我有一个Utility类。在本课程中,我只公开了两个公共函数:

public static boolean checkCustomerEligiblity(HttpServletRequest request)
public static boolean checkCartEligiblity(HttpServletRequest request)

这些方法的每一个实现都非常混乱(我没有实现这个方法)。为了将来参考,我想了解在这种情况下我们可以实现的最佳方式。

还要记住,在FALSE条件下,我们不应该退出或返回。我们必须记录FALSE条件并进行其他检查。

public static Boolean checkCustomerEligiblity(HttpServletRequest request) {
      if (Flags) { //Check if Flags are ON, only then proceed with rest         
        if (Type of customer) { //Restrict only to certain type of customers
          if (Customer within limit) { //Check customer’s available cash limit in account

          } else reasons.add(“Customer not within limit”);
        } else reasons.add(“Customer type not supported”);

        if (Customer account is NULL) {…}
        if (Customer skipped verification with photo ID) {…}
        if (Customer’s organization has opted in the plan) {…}
        if (Customer’s bill is combined bill) {…}
        if (Customer has past due on his account) {…}
        if (Customer’s credit rating is good) {…}
        if (Customer’s account is active) {…}
        if (Customer has not opted for this plan already) {…}

        ...around 15-20 If conditions more...
      }
}

checkCartEligibility()方法采用相同的结构。

我的问题是 -

1)使用策略或命令设计模式来实现上述目标是否过于笨拙?

例如,

public interface Validator {
   Boolean validate(HttpServletRequest);
}

public class CustomerCreditValidator implements Validator {…}
public class FlagValidator implements Validator {…}
public class AccountVerificationValidator implements Validator {…}
public class OrderTypeValidator implements Validator {…}
public class CartValidator implements Validator {…}

...等等大约10-15个验证器类(我可以在同一个类中组合几个校验来降低这些类的数量)。

List<Validator> validators = new ArrayList<>();

validators.add(new CustomerCreditValidator());  
validators.add(new FlagValidator());
validators.add(new AccountVerificationValidator());
validators.add(new OrderTypeValidator());
validators.add(new CartValidator());`

......等其他课程。

for (Validator validator : validators) {
   boolean result = validator.validate(request);
   if (result) {
      ...
}

2)如果上述方法过于繁琐,那么你会建议实现上述逻辑的其他设计模式是什么?

3)顺便说一下,每个验证检查都是私有的,那么我可以将所有上述验证器类作为内部类吗?

非常感谢任何帮助!

4 个答案:

答案 0 :(得分:2)

策略和命令等设计模式旨在解决松散耦合组件方面的问题。这对于代码重用是有利的,并且它可以对于可以容易地添加新特征或者容易修改现有特征的设计是有利的。但是,这些模式对于没有预料到这种需求的代码的一般组织并不特别有用。

  

使用策略或命令设计模式来实现上述内容会不会太笨拙吗?

看起来似乎会产生比现在更多的代码,当然还有更多单独的类,以及一些你现在根本不需要的粘合代码。假设所有新类都是单一用途,似乎可能就是这种情况,我不能说我看到任何诱惑。

  

如果上述方法过于繁琐,那么您会建议实现上述逻辑的其他设计模式是什么?

我认为这种情况不一定要求命名模式,只是为了更好的风格。特别是,我会考虑将每个单独的检查编写为一个单独的私有方法,而不是将它包装在自己的类中。然后,公共检查方法将主要或甚至完全由一系列单独检查方法的调用组成。

  

顺便说一下,每个验证检查都是私有的,所以我可以将上述所有验证器类都作为内部类吗?

如果你确实使用了验证器类,那么你可以使这些类成为私有嵌套类,无论是内部类还是静态嵌套类。但是你现在提出的情况甚至更多地告诉我,这种方法会有点过分。首先尝试将其分解为多种方法。

答案 1 :(得分:1)

正如约翰·博林格所说,我不认为增加课程数量会使你的条件逻辑更加干净。

在这里你可以改进的地方是使用辅助方法来处理每种类型的检查方式。

例如,可以使用常用方法提取这些条件,如果条件匹配,则验证并将原因添加到reasons

例如:

而不是

 if (!Customer within limit) {
     reasons.add(“Customer not within limit”);
  }

你可以打电话:

validCustomerInLimit(reasons, customer);

而不是

 if (Customer account is NULL) 
     reasons.add(“Customer account is null”);
  }

你可以打电话:

validCustomerAccountNotNull(reasons, customer);

更有效的实现方法是为您执行的每个验证设置一个专用的类。 通过这种方式,reasons和客户可以是实例字段,您可以直接调用帮助方法,而无需提供reasonscustomer作为参数。

你可以直接这样做:

ValidatorCustomer validatorCustomer = new ValidatorCustomer(request);
validatorCustomer.validAccountInLimit();
validatorCustomer.validAccountNotNull();

答案 2 :(得分:1)

对于这样的场景,我会站出来并建议 - 构建模式。请听我说。

例如,

我们有一个班级:

public class BaseValidator {
    private final List<CustomException> exceptions;

    private BaseValidator(final Validator validator) {
        exceptions = new ArrayList<CustomException>(validator.exceptionsAll);
    }

    public boolean hasException() {
       return exceptions.isEmpty();
    }

    public List<CustomException> getAllExceptions() {
       return exceptions;
    }

    public void throwFirstExceptionIfAny() throws CustomException {
       if (!exceptions.isEmpty()) {
          throw exceptions.get(0);
       }
    }

    public static class Validator {
        private final List<CustomException> exceptionsAll = new ArrayList<CustomException>();

        public Validator flag(String FLAG_NAME) {
           if (request.getSession().getConfigurables().getFlag(FLAG_NAME))
             ...
           else exceptionsAll.add(new CustomException(“Flag is OFF”));
        }

        public Validator credit(long CreditScore) {
           if (CreditScore > 100) {
             ...
           } else exceptionsAll.add(new CustomException(“Credit score less than required”));

           return this;
        }

        public Validator account(CustomerAccount account) {
           //Do account verification, else add new CustomeException() to exceptionsAll

           return this;
        }

        public Validator ordertype(String orderType) {
           ...
           return this;
        }

        public Validator agreement(Boolean hasDeclinedAgreement) {
           ...
           return this;
        }

        …so on for other condition checks

        public BaseValidator validate() {
           return new BaseValidator(this);
        }
    }

现在我们可以像这样使用它。假设我必须验证客户:

BaseValidator customerValidation = 
                new Validator()
                .flag(getConfigurables().getFlag()).
                .account(request.getSession().getAccount())
                .agreement(request.getSession().hasDeclinedAgreement())
                .validate();

If (customerValidation.hasException())
    List<CustomException> all = customerValidation.getAllExceptions();

如果我必须验证购物车,我可以调用不同的验证方法:

BaseValidator cartValidation = new Validator()
    .flag(getConfigurables().getFlag())
    .ordertype(…)
    …
    …
    .validate();

cartValidation.throwFirstExceptionIfAny();

我知道我们传统上不使用Builder Pattern进行验证,但是我们可以用这种方式来清理吗?

答案 3 :(得分:0)

您可以看一下弹簧状态机。我们在项目中广泛使用了涉及多个步骤的步骤,每个步骤都有自己的一组验证。