javax.inject包


javax.inject包

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() {...}
}

我們必須權衡這兩種方式:

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

而且,這幾種方法都限制了單元測試,例如,如果我們使用工廠方法,所有依賴於依賴於工廠類的測試代碼都需要模擬出factory,還要記得在用完之后清理掉它

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

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

依賴注入解決了所有的這些問題

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

構造器進一步的將依賴層層傳遞,直到滿足全部依賴。例如,我們需要構造一個StopwatchWidget實例:

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

構造器做了什么

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

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

在測試用例中,我們也可以直接通過像構造器傳遞模擬數據進行單元測試,再也不需要設置/清理factories了

void testStopwatch() {
    Stopwatch sw = new Stopwatch(new MockTimeSource());
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM