2017-04-20 43 views
2

我有一种方法可以执行多个验证,这些验证依赖于较早的验证。这纯粹是一个没有表单/前端的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这是一个很大的担心。

请建议什么是正确的方法来处理这个问题。

谢谢。

+0

[代码审查(https://codereview.stackexchange.com/)是你在找什么。 –

回答

0

这是一个小例子,可能是您的一个解决方案。

主要思想是每个验证步骤共享一个共同的上下文。此上下文包含您的验证过程的每个信息。

接下来你有一个验证器队列。每个代表一个验证步骤。验证器更改上下文(如添加商人对象),调用验证方法并在必要时更改上下文的结果。

验证过程本身只是遍历队列寻找失败的验证器。

只需运行此代码即可。也许它可以帮助:

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 
    } 
} 
+0

这听起来很完美的解决方案。我会尝试重构基于此的代码并在此处进行更新。谢谢@Obenland –

+0

你指的是https://docs.oracle.com/javase/7/docs/api/javax/naming/Context.html'javax.naming.Context'或者我应该添加自己的简单实现? –

+0

哦。我错过了删除这个。我认为有一个共同的上下文类可能会很好,但对于这个例子你不需要它。我确定了我的答案 – Obenland

0

您可以编写如下的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; 
     .... 
} 
+0

这就是我已经在做的事情。所有的业务逻辑都在这个方法之外。只有流程是在这一个,但所有单独的方法返回的结果,我必须检查是否有效/无效,并基于该进行到下一步。 –

+0

您正在将4行验证结果移至其他某种方法。让我把processPayment方法也。 –

+0

在这种情况下'doAllValidations'方法变得更大,而不是'processPayment'。 –