2015-03-07 6 views
5

Ich habe einen "Legacy" -Code, den ich umgestalten möchte.
Der Code führt grundsätzlich einen Remote-Aufruf an einen Server aus und erhält eine Antwort zurück. Dann wird entsprechend der Antwort entsprechend ausgeführt.
Beispiel des Skeletts des Codes:Bestes Entwurfsmuster/Ansatz für eine lange Liste von if/else/Ausführen von Zweigen des Codes

public Object processResponse(String responseType, Object response) { 
    if(responseType.equals(CLIENT_REGISTERED)) { 
     //code 
     //code ... 
    } 
    else if (responseType.equals(CLIENT_ABORTED)) { 
     //code 
     //code.... 
    }  
    else if (responseType.equals(DATA_SPLIT)) { 
     //code 
     //code... 
    } 
    etc 

Das Problem besteht darin, dass es viele-many sind, wenn/sonst Zweige und der Code innerhalb jedes wenn nicht trivial ist.
So wird es schwer zu pflegen.
Ich frage mich, was ist das beste Muster dafür?
Ein Gedanke, den ich hatte, war ein einzelnes Objekt mit Methodennamen die gleiche wie der responseType zu erstellen und dann innerhalb von processResponse nur mit Reflection die Methode mit dem gleichen Namen wie der responseType aufrufen.
Dies würde ProzessResponse bereinigen, aber es verschiebt den Code auf ein einzelnes Objekt mit vielen/vielen Methoden und ich denke, Reflexion würde zu Leistungsproblemen führen.
Gibt es ein schönes Design Ansatz/Muster, um dies zu bereinigen?

Antwort

6

zwei Ansätze:

  1. Strategiemuster http://www.dofactory.com/javascript/strategy-design-pattern
  2. Wörterbuch erstellen, in dem Schlüssel Metadaten (Metadaten in Ihrem Fall ist response) und Wert ist eine Funktion.

Zum Beispiel:

Diesen in Konstruktor

responses = new HashMap<string, SomeAbstraction>(); responses.Put(CLIENT_REGISTERED, new ImplementationForRegisteredClient()); responses.Put(CLIENT_ABORTED, new ImplementationForAbortedClient());

wo ImplementationForRegisteredClient und ImplementationForAbortedClientSomeAbstraction

implementieren und nennen dieses Wörterbuch über responses.get(responseType).MethodOfYourAbstraction(SomeParams);

Wenn Sie dem DI-Prinzip folgen möchten, können Sie dieses Dictionary in Ihre Client-Klasse einfügen.

+0

In der Strategie-Muster, aber wie verwende ich die richtige Strategie zur Laufzeit? Z.B. In http://en.wikipedia.org/wiki/Strategy_pattern#Java wird nur eine Instanz einer Strategie festgeschrieben, während jeder Server antwortet, wie würde ich die richtige Strategie effizient nutzen? – Jim

+0

TBH das Wörterbuch Beispiel obwohl gut, IMO ist kein Code wir schreiben normalerweise in Java – Jim

+0

@Jim Entschuldigung, ich sah in den Tags und Java automatisch an Javascript gedacht. Ich aktualisiere meine Antwort –

2

Mein erster Schnitt wäre die if/else if Strukturen mit Schaltern/Fall zu ersetzen:

public Object processResponse(String responseType, Object response) { 
    switch(responseType) { 
     case CLIENT_REGISTERED: { 
     //code ... 
    } 
    case CLIENT_ABORTED: { 
     //code.... 
    }  
    case DATA_SPLIT: { 
     //code... 
    } 

Von dort würde ich wahrscheinlich jeden Block als eine Methode extrahieren, und von dort mit dem Strategie-Muster anwenden. Stoppen Sie an welchem ​​Punkt auch immer sich richtig anfühlt.

+0

Im Strategie-Muster, aber wie verwende ich die richtige Strategie zur Laufzeit? Z.B. In http://en.wikipedia.org/wiki/Strategy_pattern#Java wird nur eine Instanz einer Strategie festgeschrieben, während jeder Server antwortet, wie würde ich die richtige Strategie effizient nutzen? – Jim

0

Der Fall, den Sie beschreiben, scheint perfekt zu der Anwendung von Strategie Muster passen. Insbesondere haben Sie viele Varianten eines Algorithmus, d. H. Der Code wird entsprechend der Antwort des Remote-Server-Aufrufs ausgeführt.

Umsetzung der Stategy Muster bedeutet, dass Sie eine Klasse Hierachie zu definieren, wie die folgenden:

public interface ResponseProcessor { 
    public void execute(Context ctx); 
} 
class ClientRegistered implements ResponseProcessor { 
    public void execute(Context ctx) { 
     // Actions corresponding to a client that is registered 
     // ... 
    } 
} 
class ClientAborted implements ResponseProcessor { 
    public void execute(Context ctx) { 
     // Actions corresponding to a client aborted 
     // ... 
    } 
} 
// and so on... 

Der Context Typ alle Informationen enthalten sollte, die jede ‚Strategie‘ zur Ausführung benötigt werden.Beachten Sie, dass, wenn verschiedene Strategien einige Algorithmusstücke teilen, Sie auch Tempate Methode Muster unter ihnen verwenden können.

Sie benötigen eine Fabrik, um eine bestimmte Strategie zur Laufzeit zu erstellen. Die Fabrik wird ausgehend von der erhaltenen Antwort eine Strategie entwickeln. Eine mögliche Implementierung sollte die von @Sattar Imamov vorgeschlagene sein. Die Fabrik enthält den Code if .. else.

Wenn Strategieklassen nicht zu schwer zu erstellen sind und zum Zeitpunkt der Erstellung keine externen Informationen benötigen, können Sie jede Strategie auch einem Enumeration-Wert zuordnen.

public enum ResponseType { 
    CLIENT_REGISTERED(new ClientRegistered()), 
    CLIENT_ABORTED(new ClientAborted()), 
    DATA_SPLIT(new DataSplit()); 

    // Processor associated to a response 
    private ResponseProcessor processor; 

    private ResponseType(ResponseProcessor processor) { 
     this.processor = processor; 
    } 
    public ResponseProcessor getProcessor() { 
     return this.processor; 
    } 
}