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 可以作为实例字段,您可以直接调用辅助方法而无需提供 reasons
或 customer
作为参数。
你可以直接做:
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状态机。我们在涉及多个步骤的项目中广泛使用,每个步骤都有自己的一组验证。
假设我有一个实用程序 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 可以作为实例字段,您可以直接调用辅助方法而无需提供 reasons
或 customer
作为参数。
你可以直接做:
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状态机。我们在涉及多个步骤的项目中广泛使用,每个步骤都有自己的一组验证。