Java多步验证方法 - 重构
我有一种方法可以执行多个验证,这些验证依赖于较早的验证。这纯粹是一个没有表单/前端的REST服务。例如Java多步验证方法 - 重构
public Json processPayment(User user, Amount amount, CardData cardData) {
Json result = new Json();
Json userResult = validateUser(user);
if (userResult.isNotValid())
result.put("errorCode", userResult.get("errorCode");
result.put("message", userResult.get("message");
return result;
}
Merchant merchant = getMerchant(user);
Json merchantResult = validateMerchant(user);
if (merchantResult.isNotValid())
result.put("errorCode", merchantResult.get("errorCode");
result.put("message", merchantResult.get("message");
return result;
}
Json limitsResult = validateLimits(user, merchant, amount);
if (limitsResult.isNotValid())
result.put("errorCode", limitsResult.get("errorCode");
result.put("message", limitsResult.get("message");
return result;
}
// Like above there are few more steps.
.
.
.
// All validations are fine process transaction.
Json transactionResult = processTransaction(user, merchant, amount, cardData);
if (transactionResult.isNotValid())
result.put("errorCode", transactionResult.get("errorCode");
result.put("message", transactionResult.get("message");
} else {
result.put("message", "Transaction Successful");
result.put("referenceNumber, transactionResult.get("rrn");
}
return result;
}
在每个步骤中,如果结果是无效的,那么就应该立即与返回错误消息,否则继续下一步。
由于多个步骤,此方法变得太大,几乎不可能进行单元测试。
我想将此方法分解为更小的方法。我已经将每个步骤的所有业务逻辑转变为单独的方法,但流程依然存在于这个大方法中。
Sonarlint CC是47这是一个很大的担心。
请建议什么是正确的方法来处理这个问题。
谢谢。
这是一个小例子,可能是您的一个解决方案。
主要思想是每个验证步骤共享一个共同的上下文。此上下文包含您的验证过程的每个信息。
接下来你有一个验证器队列。每个代表一个验证步骤。验证器更改上下文(如添加商人对象),调用验证方法并在必要时更改上下文的结果。
验证过程本身只是遍历队列寻找失败的验证器。
只需运行此代码即可。也许它可以帮助:
import java.util.*;
interface PaymentValidatorInterface {
public boolean validate(PaymentValidationContext context);
}
class PaymentValidationContext {
String result = "";
String user;
int cardData;
String merchant;
public PaymentValidationContext(String user, int cardData) {
this.user = user;
this.cardData = cardData;
}
}
class PaymentValidator {
public static boolean validateUser(PaymentValidationContext context) {
if (context.user == null) {
context.result += "User is wrong\n";
return false;
}
return true;
}
public static boolean validateMerchant(PaymentValidationContext context) {
context.merchant = context.user + "#" + context.cardData;
if (context.merchant.length() <= 3) {
context.result += "Marchant is wrong\n";
return false;
}
return true;
}
public static boolean finishValidation(PaymentValidationContext context) {
context.result += "Everything is fine.\n";
return true;
}
}
public class Processor {
private final static Queue<PaymentValidatorInterface> validators = new LinkedList<>();
static {
validators.add(PaymentValidator::validateUser);
validators.add(PaymentValidator::validateMerchant);
validators.add(PaymentValidator::finishValidation);
}
public String processPayment(String user, int cardData) {
PaymentValidationContext context = new PaymentValidationContext(user, cardData);
validators.stream().anyMatch(validator -> !validator.validate(context));
return context.result;
}
// For testing -------
public static void main(String[] args) {
Processor p = new Processor();
System.out.print(p.processPayment("Foobar", 1337)); // ok
System.out.print(p.processPayment(null, 1337)); // fails
System.out.print(p.processPayment("", 1)); // fails
}
}
这听起来很完美的解决方案。我会尝试重构基于此的代码并在此处进行更新。谢谢@Obenland –
你指的是https://docs.oracle.com/javase/7/docs/api/javax/naming/Context.html'javax.naming.Context'或者我应该添加自己的简单实现? –
哦。我错过了删除这个。我认为有一个共同的上下文类可能会很好,但对于这个例子你不需要它。我确定了我的答案 – Obenland
您可以编写如下的doValidation()
函数。
private doValidation(Json validationResult, Json result) {
if (validationResult.isNotValid())
result.put("errorCode", validationResult.get("errorCode");
result.put("message", validationResult.get("message");
return false;//validation failed
}
return true;//validation passed
}
和processPayment()
方法调用此方法。
public Json processPayment(User user, Amount amount, CardData cardData) {
Json result = new Json();
if(!doAllValidations(user,amount,cardData, result))
return result;
// All validations are fine process transaction.
Json transactionResult = processTransaction(user, merchant, amount, cardData);
if (transactionResult.isNotValid())
result.put("errorCode", transactionResult.get("errorCode");
result.put("message", transactionResult.get("message");
} else {
result.put("message", "Transaction Successful");
result.put("referenceNumber, transactionResult.get("rrn");
}
return result;
}
最后,如果需要,您可以将所有验证移动到其他方法。
public bool doAllValidations(User user, Amount amount, CardData cardData, result) {
Json userResult = validateUser(user);
if (!doValidation(userResult, result))
return result;
Merchant merchant = getMerchant(user);
Json merchantResult = validateMerchant(user);
if (!doValidation(merchantResult, result))
return result;
Json limitsResult = validateLimits(user, merchant, amount);
if (!doValidation(limitsResult, result))
return result;
....
}
这就是我已经在做的事情。所有的业务逻辑都在这个方法之外。只有流程是在这一个,但所有单独的方法返回的结果,我必须检查是否有效/无效,并基于该进行到下一步。 –
您正在将4行验证结果移至其他某种方法。让我把processPayment方法也。 –
在这种情况下'doAllValidations'方法变得更大,而不是'processPayment'。 –
[代码审查(https://codereview.stackexchange.com/)是你在找什么。 –