2010-12-10 47 views
4

我想instanciate相同類型的依賴樹/鏈的幾個版本使用不同的實現該樹/鏈中的一些接口。在這種情況下使用什麼是最好的Guice練習/模式?在Guice中管理多個版本的相同依賴關係樹的最佳模式是什麼?

這是我的問題的具體例子。

我有一個Writer接口,它可能是一個文件編寫器或一個std-out編寫器,它將位於我的依賴層次結構的葉子處。例如:

interface Writer { ... } 
class FileWriter implements Writer { ... } 
class StdOutWriter implements Writer { ... } 

另一個記錄器接口用於在寫入器上添加一個間接層。例如:

interface Logger { ... } 

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

然後有一個客戶端使用記錄器。現在

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

,我想用兩種層次的在我的計劃:

  1. 客戶端 - > LoggerImpl - > FileWriter的
  2. 客戶端 - > LoggerImpl - > StdOutWriter

有沒有一種很好的方法來連接這個,而不用1和2單獨的Guice模塊?

理想我想有一個ClientFactory類是這樣的:

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

誰能想出一個辦法連線了這個使用此工廠,或以任何其他方式?

我也想要一個解決方案,可以擴展到我有更多更長的依賴關係樹/鏈種類的情況。謝謝!

回答

6

這是robot legs的問題。該解決方案基本上是使用PrivateModule來綁定每個依賴關係樹並僅公開該樹的根。有幾種方法可以做到這一點,但這裏有一個如何你通常會做一個例子(也有很多的變化對這個你可以根據自己的需要做的):

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; 
    } 

    ... 
} 

你的方法的情況下Client fileClient(File)雖然有點不同。

+0

感謝您的一個很好的解釋!我現在終於明白了私人模塊和機器人腿的問題。這爲我解決了這個問題。但是我想使用fileClient(File)變體的原因是因爲我可能不會在運行時使用客戶端的@FileOut變體(例如,這取決於命令行參數)。我可以實例化一個不同的guice模塊,具體取決於是否有文件提供,但不是很優雅,隨着依賴樹數量的增長,它會變得非常討厭。 – rodion 2010-12-11 03:33:57

相關問題