2017-04-20 26 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'。 –