2017-04-20 14 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; 
} 

結果が無効な場合は、エラーメッセージとともにすぐに戻る必要があります。それ以外の場合は、次の手順に進みます。

複数のステップがあるため、この方法は非常に大きくなり、単体テストを行うことはほとんど不可能になりました。

このメソッドを小さなものに分割したいと考えています。私は既に各ステップのすべてのビジネスロジックを別々のメソッドに移しましたが、依然としてこの大きなメソッドにはフローが残ります。

ソナーリントCCは47ですが、大きな心配です。

これを処理するには適切な方法が何であるかお勧めします。

ありがとうございます。

+0

[コードレビュー](https://codereview.stackexchange.com/は)あなたが探しているものです。 –

答えて

0

これはあなたのための解決策となりうる小さな例です。

主な考え方は、各検証ステップが1つの共通のコンテキストを共有することです。このコンテキストは、検証プロセスのあらゆる情報を保持します。

次に、バリデータのキューがあります。それぞれ1つの検証ステップを表します。バリデーターは(商人オブジェクトの追加のような)コンテキストを変更し、検証メソッドを呼び出し、必要に応じてコンテキストの結果を変更します。

検証プロセス自体は、キューを反復して、失敗したバリデータを探します。

このコードを実行してください。多分それは役立ちます:

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'の代わりに大きくなります。 –

関連する問題