web-dev-qa-db-ja.com

多くのif if条件を回避する方法

コードリファクタリングとif elseステートメントの回避に関する多くのトピックを読みました。実際、if-else条件を多く使用しているクラスがあります。

詳細:プルパーサーを使用しており、SOAPレスポンスの各行で、興味のあるタグがあるかどうかを確認し、そうでない場合は別のタグなどを確認します。

 if(eventType == XmlPullParser.START_TAG) {
            soapResponse= xpp.getName().toString();

            if (soapResponse.equals("EditorialOffice")){  
                eventType = xpp.next();
                if (xpp.getText()!=null){
                editorialOffice += xpp.getText();
                }
            }   
            else if (soapResponse.equals("EditorialBoard")){  
                eventType = xpp.next();
                if (xpp.getText()!=null){
                editorialBoard += xpp.getText();
                }
            }
            else if (soapResponse.equals("AdvisoryBoard")){  
                eventType = xpp.next();
                if (xpp.getText()!=null){
                advisoryBoard += xpp.getText();
                }
            }   
        }
        eventType = xpp.next();
     }

さて、if else条件の代わりにsomethimg elseを使用したいのですが、何がわからないのですか。

例や良いチュートリアルページを教えてください。

ありがとうございました。

38
Miloš

この特定のケースでは、追加される文字列を除いて、3つのケースすべてでコードが本質的に同一であるため、構築される各文字列のマップエントリがあります。

Map<String,String> map = new HashMap<String,String>();
map.put("EditorialOffice","");
map.put("EditorialBoard","");
map.put("AdvisoryBoard","");
// could make constants for above Strings, or even an enum

次に、コードを次のように変更します

if(eventType == XmlPullParser.START_TAG) {
    soapResponse= xpp.getName().toString();
    String current = map.get(soapResponse);
    if (current != null && xpp.getText()!=null) {
        map.put( soapResponse, current += xpp.getText());
    }
    eventType = xpp.next();
}

「if ... then ... else」はありません。戦略パターンなどの複数のクラスの複雑さでさえありません。マップはあなたの友達です。戦略は状況によっては優れていますが、これは簡単に解決できます。

26
Kevin Welker

戦略パターンを見てみてください。

  • 応答を処理するためのインターフェイスクラスを作成します(IMyResponse)
    • このIMyResponseを使用して、AdvisoryBoardResponseクラス、EditorialBoardResponseクラスを作成します
  • Soapresponse値をキーとして、戦略を値として辞書を作成します
  • その後、辞書から取得してIMyResponseクラスのメソッドを使用できます

小さな例:

// Interface
public interface IResponseHandler {
   public void handleResponse(XmlPullParser xxp);

}

// Concrete class for EditorialOffice response
private class EditorialOfficeHandler implements IResponseHandler {
   public void handleResponse(XmlPullParser xxp) {
       // Do something to handle Editorial Office response
   }
}

// Concrete class for EditorialBoard response
private class EditorialBoardHandler implements IResponseHandler {
   public void handleResponse(XmlPullParser xxp) {
       // Do something to handle Editorial Board response
   }
}

場所で、ハンドラーを作成する必要があります。

Map<String, IResponseHandler> strategyHandlers = new HashMap<String,IResponseHandler>();
strategyHandlers.put("EditorialOffice", new EditorialOfficeHandler());
strategyHandlers.put("EditorialBoard", new EditorialBoardHandler());

応答を受け取った場所:

IResponseHandler responseHandler = strategyHandlers.get(soapResponse);
responseHandler.handleResponse(xxp);
46
hwcverwe

Java 7では文字列を切り替えることができます。使用できる場合は使用できます;-)

8
Peter Perháč

Zzzzzzz(など)のコメントに加えて... XmlPullParserを使用しているので、持っているようないコードを書くことに注意してください。コードを分割して「より良い」コールバックを登録することもできますが、可能であればSimpleXMLライブラリなどを使用してください。

また、コードをリファクタリングして、読みやすく、冗長性を低くすることができます。たとえば、各ifステートメント内でxpp.next()を呼び出すのはなぜですか?なぜ一度だけ外で呼び出すのではないのですか:

if(eventType == XmlPullParser.START_TAG) {
    soapResponse= xpp.getName().toString();
    if (soapResponse.equals("EditorialOffice") && xpp.getText()!=null){  
        editorialOffice += xpp.getText();
    }   
    else if (soapResponse.equals("EditorialBoard") && xpp.getText()!=null){  
        editorialBoard += xpp.getText();
    }
    else if (soapResponse.equals("AdvisoryBoard") && xpp.getText()!=null){  
        advisoryBoard += xpp.getText();
    }   
}
eventType = xpp.next();
5
Cristian

Javaを使用できるかどうかについては言及していません。そのJavaバージョンでは、 switch文の文字列 を使用できます。

それ以外は、各ケースのロジックをカプセル化することは良い考えです。例えば:

Map<String, Department> strategyMap = new HashMap<String, Department>();
strategyMap.put("EditorialOffice", new EditorialOfficeDepartment());
strategyMap.put("EditorialBoard", new EditorialBoardDepartment());
strategyMap.put("AdvisoryBoard", new AdvisoryBoardDepartment());

次に、マップから正しい戦略を選択して使用するだけです。

String soapResponse = xpp.getName();
Department department = strategyMap.get(soapResponse);
department.addText(xpp.getText());

Departmentはもちろんインターフェースにあります...

4
Alan Escreet

これは広大な質問であり、本当の答えはありません。 (そして、私は石鹸をあまり使用しません)

ここにあなたのコードに基づいたいくつかのアイデアがあります:

最初に、重複コードをグループ化できます

if (soapResponse.equals("EditorialOffice")
||soapResponse.equals("EditorialBoard")
||soapResponse.equals("AdvisoryBoard")){ 

あなたができるもう一つの良いことは、次のようなスイッチステーメントで遊ぶことです:

switch(soapResponse){
case "EditorialOffice":
case "EditorialBoard":
case "AdvisoryBoard":
eventType = xpp.next();
                if (xpp.getText()!=null){
                advisoryBoard += xpp.getText();
                }
break;

また、テストを小さな関数に分解することを検討する必要があります。

public bool interestingTag(string s){
return (soapResponse.equals("EditorialOffice")
    ||soapResponse.equals("EditorialBoard")
    ||soapResponse.equals("AdvisoryBoard"));
}

    public processData(xpp){
    eventType = xpp.next();
                    if (xpp.getText()!=null){
                    editorialBoard += xpp.getText();
                    }
    ....}

Whileループですべての回答を処理し、elseが5〜10行関数になる場合は非常に長くなるように

しかし、私が言ったように、同じことをする非常に多くの良い方法があります

4
Jason Rogers

If/else構造の各ブランチに1つずつ、3つの実装でResponseHandlerインターフェイスを作成できます。

次に、異なるsoapResponseをハンドラーにマッピングするマップ、またはそのsoapResponseを処理できる場合はすべてのハンドラーのリストを用意します。

また、ボイラープレートコードの一部を、応答ハンドラクラスの一般的な可能性のある抽象的な実装に移動できる必要があります。

多くの場合、これには多くのバリエーションがあります。コードの複製を利用することにより、実際に必要な実装は1つだけです。

class ResponseHandler{
    String stringToBuild = "" // or what ever you need
    private final String matchString

    ResponseHandler(String aMatchString){
        matchString = aMatchString
    }
    void handle(XppsType xpp){
        if (xpp.getName().toString().equals(matchString){
            eventType = xpp.next();
            if (xpp.getText()!=null){
                 editorialOffice += xpp.getText();
            }
        }
    }
}

あなたのコードは

List<ResponseHandler> handlers = Arrays.asList(
    new ResponseHandler("EditorialOffice"),
    new ResponseHandler("EditorialBoard"),
    new ResponseHandler("AdvisoryBoard"));
if(eventType == XmlPullParser.START_TAG) {
    for(ResponseHandler h : handlers)
        h.handle(xpp);
}
3
Jens Schauder

次のような列挙型を定義できます。

public enum SoapResponseType {
    EditorialOffice(1, "description here") {
        public void handle(XmlPullParser xpp) {
            //do something you want here
            return null;
        }
    },
    EditorialBoard(2, "description here") {
        public void handle(XmlPullParser xpp) {
            //do something you want here
            return null;
        }
    },
    AdvisoryBoard(3, "description here") {
        public void handle(XmlPullParser xpp) {
            //do something you want here
            return null;
        }
    };

    public static SoapResponseType nameOf(String name) {
        for (SoapResponseType type : values()) {
            if (type.getName().equalsIgnoreCase(name)) {
                return type;
            }
        }
        return null;
    }

    public void handle(XmlPullParser xpp) {
        return null;
    }
}

上記の列挙型を次のように使用します。

SoapResponseType type = SoapResponseType.nameOf("input string");
if (type != null) {
    type.handle(xpp);
}

それはきれいなコードですよね!

2
Xuelian Han