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

Java - Design Pattern to solve multiple conditionals logic

假设我有一个实用程序 class。在这个 class 中,我只公开了 2 个 public 函数:

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

这几个方法的实现真的很乱(我没有实现这个方法)。为了将来参考,我想了解我们在这种情况下可以实施的最佳方式。

还要记住的一点是,在 FALSE 条件的情况下,我们不应该退出或 return。我们必须记录 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)用Strategy或者Command设计模式来实现上面会不会太笨重?

例如,

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 个验证器 classes(我可以在同一个 class 中组合几个检查以减少此类 classes 的数量) .

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());`

…其他 classes.

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

2) 如果上述方法也太繁琐,那么您会建议 is/are 其他设计模式是什么来实现上述逻辑?

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

非常感谢任何帮助!

Strategy 和 Command 等设计模式旨在解决 loosely-coupled 组件方面的问题。这可能有利于代码重用,并且 可能 有利于可以轻松添加新功能或轻松修改现有功能的设计。但是,这些模式对于没有预期此类需求的一般代码组织不是特别有用。

Will it be too unwieldy to use Strategy or Command design pattern to implement the above?

看起来确实会产生比现在多得多的代码,而且肯定会有更多独立的 classes,以及一些您现在根本不需要的粘合代码。假设所有新的 classes 都将是 single-use,看起来很可能是这样,我不能说我看到任何吸引力。

If the above approach is going to be too cumbersome too, what is/are the other design pattern(s) would you propose the implement the above logic?

我认为这种情况不一定需要命名模式,而只是为了更好的风格。特别是,我会考虑将每个单独的检查编写为单独的私有 方法 ,而不是将其包装在自己的 class 中。 public 检查器方法将主要或什至全部由对单个检查方法的一系列调用组成。

By the way, each of the validation checks are private, so can I have all the above validator classes as inner classes only?

如果你确实使用了验证器 classes 那么你可以使那些 classes 私有嵌套 classes,是的,无论是内部 classes 还是静态嵌套那些。但你现在提出的情况更让我觉得这样的做法未免有些矫枉过正。首先尝试将其分解为多种方法。

作为 John Bollinger,我也不认为乘以 classes 的数量会使您的条件逻辑更清晰。

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

例如,这些条件可以在常用方法中提取,如果条件匹配,这些方法会验证并将原因添加到 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);

一个更有效的实现是为您执行的每个验证实例化一个专用的 class。 这样,reasons 和 customer 可以作为实例字段,您可以直接调用辅助方法而无需提供 reasonscustomer 作为参数。

你可以直接做:

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

对于这种情况,我会冒险提出——构建模式。请听我说完。

例如,

让我们有一个class:

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

我知道我们传统上不会将构建器模式用于验证目的,但我们可以通过这种方式使用它来清理吗?

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