Guice 可以透過程式碼的設定,動態決定注入介面時,要選擇的實作類別。
動態選擇實作類別
以下的範例延續前文,主要是在前文的程式碼上做修正。
1、建立 Provider 以指派不同的實作類別
假設我現在除了原有的 ImplementationA 以外,還有第二種實作類別 ImplementationB想要依照某個變數來決定要注入 ImplementationA 或 ImplementationB。
選擇的方法是透過 Provider 來決定。
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 處取得。
/**
* 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
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
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());
}
}
執行結果如下:
Set IMPL to 'a'. Implementation of my interface: ImplementationA Set IMPL to 'b'. Implementation of my interface: ImplementationB
沒有留言:
張貼留言