為什麼需要“依賴注入”
Case 1
public class Foo {
private Bar bar;
public Foo() {
bar = new Bar();
}
public void doSomething(int key) {
String result = bar.getResult(key);
//swithch result
}
}
反模式 ,在建構函式中,初始化了合作類,導致:
• 外部使用者不知道 Foo 裡面還依賴了 Bar
• 無法對Bar單元測試,體現在 bar.getResult() 返回真實值,如果和網路、資料庫、IO 打交道的話,這是一個很耗時的動作
Case 2
public class Foo {
private Bar bar=new Bar();
public Foo(){
}
public void doSomething(int key){
String result = bar.getResult(key);
//swithch result
}
}
反模式,雖然沒有在建構函式中初始化 Bar 物件,但在欄位中直接初始化了 Bar 物件,問題和上面一樣
Case 3 使用 Guice 來對依賴進行管理
public class Foo {
private Bar bar ;
public Foo(Bar bar) {
this.bar = bar;
}
public String doSomething(int key) {
return bar.getResult(key);
}
}
對於使用 Foo 的使用者而言,一眼就知道 Foo 內部需要 合作類 Bar, 明白了 Foo 的職責,同時 @Inject 將依賴物件注入,解耦的同時還方便測試
public class TestCase {
private Bar bar;
public void before(){
MockitoAnnotations.initMocks(this);
}
public void test(){
//Arrange
when(bar.getResult(eq(1))).thenReturn("jack");
Foo foo=new Foo(bar);
//Action
String result = foo.doSomething(1);
//Assert
Assert.assertEquals("jack",result);
}
}
上面可以看到,Mock 了 Bar 物件,Bar 物件的 getResult() 可能是一個比較耗時的功能,所以對它進行了Stub,同時 Foo 不依賴真實的 Bar 物件。