Guice 可以透過程式碼的設定,動態決定注入介面時,要選擇的實作類別。
動態選擇實作類別
以下的範例延續前文,主要是在前文的程式碼上做修正。
1、建立 Provider 以指派不同的實作類別
假設我現在除了原有的 ImplementationA 以外,還有第二種實作類別 ImplementationB想要依照某個變數來決定要注入 ImplementationA 或 ImplementationB。
選擇的方法是透過 Provider 來決定。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public static class InterfaceProvider implements Provider<MyInterface> { @Override public MyInterface get() { switch (IMPL) { case "a" : return new ImplementationA(); case "b" : return new ImplementationB(); default : return null ; } } } |
這個 Provider 中,會依照 IMPL 這個全域的字串變數來決定實作類別是 ImplementationA 還是 ImplementationB。
2、調整 configure()
另一件要做的調整,是在 MyModule 類別中的 configure() 方法
原本是利用 bind-to 的方法來指派注入的實作目標
這裡要改為 bind-toProvider 的形式,也就是並不直接在 configure() 中指定目標
而是指定要從 Provider 處取得。
1 2 3 4 5 6 7 8 9 |
/** * Configuring the injection of interfaces. */ public static class MyModule extends AbstractModule { @Override protected void configure() { bind(MyInterface. class ).toProvider(InterfaceProvider. class ); } } |
3、調整完的完整程式碼與執行結果
綜合了(一)和上述的調整,調整後完整的程式碼如下,分為 Main.java 以及 RunningService.java 兩支程式。
Main.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
package tw.twgogo.jimwayne.guice; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Provider; public class Main { private static String IMPL = "a" ; /** * Interface which can be injected automatically. */ public static interface MyInterface { /** * Get the class name of the implementation. * @return */ public String getClassName(); } /** * An implementation for MyInterface. */ public static class ImplementationA implements MyInterface { @Override public String getClassName() { return "ImplementationA" ; } } /** * An implementation for MyInterface. */ public static class ImplementationB implements MyInterface { @Override public String getClassName() { return "ImplementationB" ; } } public static class InterfaceProvider implements Provider<MyInterface> { @Override public MyInterface get() { switch (IMPL) { case "a" : return new ImplementationA(); case "b" : return new ImplementationB(); default : return null ; } } } /** * Configuring the injection of interfaces. */ public static class MyModule extends AbstractModule { @Override protected void configure() { bind(MyInterface. class ).toProvider(InterfaceProvider. class ); } } public static void main(String[] args) { // Initiate the injection through Guice. Injector injector = Guice.createInjector( new MyModule()); // Use Guice to inject and get the instance. IMPL = "a" ; System.out.println( "Set IMPL to 'a'." ); injector.getInstance(RunningService. class ).print(); IMPL = "b" ; System.out.println( "Set IMPL to 'b'." ); injector.getInstance(RunningService. class ).print(); } } |
其中上述程式碼最後的 main(),可以看到連續做了兩次取得 RunningService 的 instance
並且呼叫 print() 方法,以觀察調整 IMPL 全域變數時,會對結果造成什麼影響。
RunningService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package tw.twgogo.jimwayne.guice; import tw.twgogo.jimwayne.guice.Main.MyInterface; import com.google.inject.Inject; public class RunningService { private MyInterface impl; @Inject public RunningService (MyInterface myInterface) { this .impl = myInterface; } public void print () { System.out.println( "Implementation of my interface: " + this .impl.getClassName()); } } |
執行結果如下:
1 2 3 4 |
Set IMPL to 'a'. Implementation of my interface: ImplementationA Set IMPL to 'b'. Implementation of my interface: ImplementationB |
沒有留言:
張貼留言