2016-03-28 1 views
3

Ich möchte die API-Methode eines externen Herstellers für Typen in meiner lokalen Bibliothek aufrufen. Die Methode des Anbieters verwendet eine Einstellung in Form einer Zeichenfolge, die mehrere Werte annehmen kann, z. B. "Cat" und "Dog". Ich bin der Durchführung der Zuordnung von meiner Art, um die Einstellung Zeichenfolge des Anbieters so:Effizientes Entwurfsmuster zum Ausführen von Eins-zu-Eins-Zuordnungen von einer Typhierarchie zu einer Gruppe von Werten

public class Program { 
    interface LocalType {} 
    static class LocalCat implements LocalType {} 
    static class LocalDog implements LocalType {} 

    // Calls some API to get the animal's sound 
    interface AnimalSounds { 
     void playSound(LocalType t); 
    } 

    // Vendor-specific implementation 
    static class VendorSounds implements AnimalSounds{ 
     private static VendorAPI api = new VendorAPI(); 
     @Override public void playSound(LocalType t) { 
      // Map local type to vendor setting 
      if (t instanceof LocalCat) 
       api.vendorMethod("Cat"); 
      else if (t instanceof LocalDog) 
       api.vendorMethod("Dog"); 

     } 
    } 

    // API defined externally by vendor (reproduced here for illustration) 
    static class VendorAPI { 
     static void vendorMethod(String type) { 
      // Do something 
     } 
    } 

    public static void main(String[] args) { 
     AnimalSounds s = new VendorSounds(); // Choose vendor 
     s.playSound(new LocalCat()); // For example 
    } 
} 

Hier "Cat" und "Dog" sind herstellerspezifische Einstellungen; Ich kann später zu einem französischen Verkäufer wechseln, wo diese zwei "Chat" bzw. "Chien" sind. Um zu vermeiden, herstellerspezifische Informationen in die Hierarchie LocalType hinzuzufügen, die dann jedes Mal geändert werden musste, wenn ich die Anbieter ändere, versteckte ich diese Zuordnung in einer Art Adapter AnimalSounds (ich fügte VendorSounds als Beispiel für einen Hersteller hinzu).

Aber die Kaskade von instanceof riecht nach schlechtem Design für mich, gibt es vielleicht einen eleganteren Weg, dies zu erreichen, was ich übersehen habe?

Antwort

2

Wenn Sie die Zuordnung vollständig außerhalb Ihres lokalen Arten behalten möchten, können Sie eine Map<Class,String> bauen könnte, und es statt einer Kette von instanceof -basierte conditionals verwenden:

static final Map<Class,String> vendorMethodMap = new HashMap<>; 
static { 
    // The data for this map could come from a configuration file of sorts 
    vendorMethodMap.put(LocalCat.class, "Cat"); 
    vendorMethodMap.put(LocalDog.class, "Dog"); 
} 

Jetzt playSound Ihre Methode würde wie folgt aussehen:

@Override public void playSound(LocalType t) { 
    api.vendorMethod(vendorMethodMap.get(t.getClass())); 
} 
1

dies in allgemeinerer Art und Weise zu lösen, können Sie die Besuchermuster verwenden. Die Betonelementklassen akzeptieren Klassen einen Besucher-Schnittstelle implementiert:

public class Program { 

    interface LocalTypeVisitor { 
     void visit(LocalDog dog); 
     void visit(LocalCat cat); 
    } 

    interface LocalType { 
     void accept(LocalTypeVisitor visitor); 
    } 
    static class LocalCat implements LocalType { 
     @Override public void accept(LocalTypeVisitor visitor) { 
      visitor.visit(this); 
     } 
    } 
    static class LocalDog implements LocalType { 
     @Override public void accept(LocalTypeVisitor visitor) { 
      visitor.visit(this); 
     } 
    } 

    // API defined externally by vendor (reproduced here for illustration) 
    static class VendorAPI { 
     void vendorMethod(String type) { 
      // Do something 
     } 
    } 

    interface Vendor extends LocalTypeVisitor {} 

    // Vendor-specific implementation 
    static class VendorSounds implements Vendor { 
     private static VendorAPI api = new VendorAPI(); 
     @Override public void visit(LocalCat cat) { 
      api.vendorMethod("Cat"); 
     } 
     @Override public void visit(LocalDog dog) { 
      api.vendorMethod("Dog"); 
     } 
    } 

    public static void main(String[] args) { 
     Vendor s = new VendorSounds(); // Choose vendor 
     new LocalCat().accept(s); // For example 
    } 
} 

Aber es ist schwieriger, neue LocalType Implementierungen zu erstellen, da es alle Besucher Wellen durch. Überlegen Sie das sorgfältig.

+0

Wie löst es das Problem? – AdamSkywalker

+0

durch Doppel-Dispatching –

+1

Ich mag dies, da es dem Besucher ermöglicht, möglicherweise einen komplexen Typ statt "void" zurückzugeben – ScarletPumpernickel