2010-12-10 4 views
4

Ich möchte mehrere Versionen der gleichen Art von Abhängigkeitsbaum/Kette instanziieren, die verschiedene Implementierungen für einige der Schnittstellen in diesem Baum/Kette verwenden. Was ist das beste Guice-Training/Muster, das man in diesem Fall verwenden kann?Was ist das beste Muster für die Verwaltung mehrerer Versionen der gleichen Abhängigkeitsstruktur in Guice?

Hier ist ein konkretes Beispiel für mein Problem.

Ich habe eine Writer Schnittstelle, die möglicherweise ein Datei-Writer oder ein std-out-Writer sein kann, der auf dem Blatt meiner Abhängigkeitshierarchie liegen wird. So etwas wie dieses:

Eine andere Logger-Schnittstelle wird verwendet, um eine Schicht von Indirection auf dem Schreiber hinzuzufügen. Zum Beispiel:

interface Logger { ... } 

class LoggerImpl{ 
    @Inject 
    public Logger(Writer out){ ... } 
    public void log(String message){ out.println(message); } 
} 

Dann gibt es einen Client, der den Logger verwendet.

class Client{ 
    @Inject 
    public Client(Logger logger){ ... } 
    public void do(){ logger.log("my message"); } 
} 

Nun würde Ich mag in meinem Programm zwei Arten von Hierarchien verwenden:

  1. Client -> LoggerImpl -> Filewriter
  2. Client -> LoggerImpl -> StdOutWriter

Gibt es eine gute Möglichkeit, dies zu verkabeln, ohne ein separates Guice-Modul für 1 und 2 zu verwenden?

Im Idealfall würde Ich mag eine ClientFactory Klasse wie diese habe:

interface ClientFactory{ 
    public Client stdOutClient(); 
    public Client fileClient(); 
    //or fileClient(File outputFile) for extra points ;) 
} 

Könnte jemand kommen mit einem Weg, um diese mit diesem Werk verkabeln oder mit anderen Mitteln?

Ich möchte auch eine Lösung, die auf Fälle skalieren würde, wo ich eine größere Vielfalt von längeren Abhängigkeitsbäumen/Ketten habe. Vielen Dank!

Antwort

6

Dies ist das robot legs Problem. Die Lösung besteht im Wesentlichen darin, PrivateModule s zu verwenden, um jede Abhängigkeitsstruktur zu binden und nur die Wurzel dieser Struktur verfügbar zu machen. Es gibt mehrere Möglichkeiten, wie Sie dies tun könnte, aber hier ist ein Beispiel dafür, wie Sie in der Regel es tun könnte (es gibt dies viele Variationen Sie nach Ihren Bedürfnissen tun):

public class ClientModule extends PrivateModule { 
    private final Writer writer; 
    private final Class<? extends Annotation> annotationType; 

    public ClientModule(Writer writer, Class<? extends Annotation> annotationType) { 
    this.writer = writer; 
    this.annotationType = annotationType; 
    } 

    @Override protected void configure() { 
    bind(Writer.class).toInstance(writer); 
    bind(Logger.class).to(LoggerImpl.class); 
    expose(Client.class).annotatedWith(annotationType); 
    } 
} 

public class ClientFactoryModule extends AbstractModule { 
    private final File file; 

    public ClientFactoryModule(File file) { 
    this.file = file; 
    } 

    @Override protected void configure() { 
    install(new ClientModule(new StdOutWriter(), StdOut.class)); 
    install(new ClientModule(new FileWriter(file), FileOut.class)); 
    bind(ClientFactory.class).to(ClientFactoryImpl.class); 
    } 
} 

public class ClientFactoryImpl implements ClientFactory { 
    private final Client stdOutClient; 
    private final Client fileClient; 

    @Inject public ClientFactoryImpl(@StdOut Client stdOutClient, 
            @FileOut Client fileClient) { 
    this.stdOutClient = stdOutClient; 
    this.fileClient = fileClient; 
    } 

    ... 
} 

Ihr Szenario eines Verfahrens Client fileClient(File) ist jedoch ein bisschen anders.

+0

Danke für eine großartige Erklärung! Ich habe nun endlich private Module und das Roboterbeineproblem verstanden. Das löst die Frage für mich. Aber der Grund, warum ich die Datei-Variante (Datei) verwenden wollte, ist, weil ich möglicherweise nicht die @FileOut-Variante des Clients zur Laufzeit verwende (das hängt zum Beispiel von einem Befehlszeilenargument ab). Ich könnte ein anderes Guice-Modul instanziieren, je nachdem, ob es eine Datei gibt oder nicht, aber es ist nicht sehr elegant, und da die Anzahl meiner Dependency-Tree-Varianten wächst, würde es ziemlich unangenehm werden. – rodion

Verwandte Themen