javax.inject包

javax.inject包

java提出的依賴注入標準,有別於如下傳統的對象獲取方式java

  • 構造方法
  • 工廠模式
  • 服務器定位模式(e.g. JNDI)

開發過程當中是會有不少層層依賴的對象的,例如,Stopwatch依賴於TimeSource,爲當前對象尋找一個所依賴對象的實例稱作解決依賴,若沒有實例被找到,則應用執行失敗,咱們稱依賴不知足服務器

當沒有依賴注入時,也有不少解決依賴的方法,例如直接調用構造器單元測試

class Stopwatch {
    final TimeSource timeSource;
    Stopwatch() {
        timeSource = new AtomicClock(...);
    }
    void start() {...}
    void stop() {...}
}

若是須要更多的靈活性,可使用工廠方法測試

class Stopwatch {
    final TimeSource timeSource;
    Stopwatch() {
        timeSource = DefaultTimeSource.getInstance();
    }
    void start() {...}
    void stop() {...}
}

咱們必須權衡這兩種方式:this

  • 構造器很簡潔,但不靈活
  • 工廠方法雖然從必定程度上解耦了調用方和具體實現,可是須要不少模版代碼
  • Service locators方式雖然實現了更好的耦合,但缺乏了編譯時的類型檢查

並且,這幾種方法都限制了單元測試,例如,若是咱們使用工廠方法,全部依賴於依賴於工廠類的測試代碼都須要模擬出factory,還要記得在用完以後清理掉它pwa

void testStopwatch() {
    // 先獲取原始的實例
    TimeSource original = DefaultTimeSource.getInstance();
    // 用mock數據替換原始實例
    DefaultTimeSource.setInstance(new MockTimeSource());
    try {
        Stopwatch sw = new StopWatch();
        ...
    } finally {
        // 將原始實例放回去以免一些風險
        DefaultTimeSource.setInstance(original);
    }
}

實踐經驗告訴咱們,模擬factor會致使大量的模式化代碼,大量的模擬和清理將會很快失控。code

依賴注入解決了全部的這些問題對象

class Stopwatch {
    final TimeSource timeSource;
    @Inject
    Stopwatch(TimeSource timeSource) {
        this.timeSource = timeSource;
    }
    void start() {...};
    void stop() {...};
}

構造器進一步的將依賴層層傳遞,直到知足所有依賴。例如,咱們須要構造一個StopwatchWidget實例:開發

class StopwatchWidget {
    @Inject
    StopwatchWidget(Stopwatch sw) {...}
}

構造器作了什麼get

  1. 找到一個TimeSource
  2. 利用TimeSource構造Stopwatch
  3. 利用Stopwatch構造StopwatchWidget

這使咱們的代碼看起來更加簡潔和靈活,並從必定程度上弱化了依賴關係

在測試用例中,咱們也能夠直接經過像構造器傳遞模擬數據進行單元測試,不再須要設置/清理factories了

void testStopwatch() {
    Stopwatch sw = new Stopwatch(new MockTimeSource());
}
相關文章
相關標籤/搜索