[Android]使用Dagger 2依賴注入 - DI介紹(翻譯)


如下內容爲原創,歡迎轉載,轉載請註明
來自每天博客:http://www.cnblogs.com/tiantianbyconan/p/5092083.html
html

使用Dagger 2依賴注入 - DI介紹

原文:http://frogermcs.github.io/dependency-injection-with-dagger-2-introdution-to-di/java

不久以前,在克拉科夫的 Tech Space 的 Google I/O 擴展中,我 展現 了一些關於使用Dagger 2來進行依賴注入。在準備期間我認識到有太多相關的東西須要去講,沒法用一打幻燈片就能覆蓋到所有。可是它能夠做爲一個很好的進入點來開展更多這一系列主題-Android端的依賴注入。git

在這一章中我會去經過以前所展現的來進行一個總結。可能並非循序漸進的 - 我認爲如今是時候打破過去,使用一些本來咱們不會使用或者不該該使用的方法來解決問題了。Jake Wharton 講述 了相關歷史(Guice, Dagger 1),Gregory Kick 也是(幾乎有一半是關於Spring, Guice, Dagger 1)。我也會花幾分鐘的時間講述之前的解決方式。可是此刻是時候開始了。程序員

依賴注入

依賴注入的所有就是構建對象並在咱們須要時把它們傳入。我不會深刻到它的學說(查看維基百科對DI的定義)。想象一個簡單的類:UserManager,它依賴UserStoreApiService。若是沒有使用依賴注入,這個類會看起來像這樣:github

UserStoreApiService 二者都是在UserManager類中構造和提供的:api

class UserManager {
    
    private ApiService apiService;
    private UserStore userStore;

    //No-args constructor. Dependencies are created inside.
    public UserManager() {
        this.apiService = new ApiSerivce();
        this.userStore = new UserStore();
    }

    void registerUser() {/*  */}

}

class RegisterActivity extends Activity {

    private UserManager userManager;

    @Override
    protected void onCreate(Bundle b) {
        super.onCreate(b);
        this.userManager = new UserManager();
    }

    public void onRegisterClick(View v) {
        userManager.registerUser();
    }
}

爲何這些代碼會給咱們製造一些問題呢?讓咱們想象一下,你但願去改變UserStore的實現,用SharedPreferences來做爲它的存儲機制。它須要至少一個Context對象來建立一個實例,因此咱們須要把它經過構造器傳入到UserStore。它意味着UserManager類中也須要被修改來使用新的UserStore構造器。如今想象下有不少類使用了UserStore - 它們所有都須要被修改。框架

如今再來看下咱們使用了依賴注入的UserManager類:異步

它的依賴是在類的外面建立和提供的:ide

class UserManager {

    private ApiService apiService;
    private UserStore userStore;

    //Dependencies are passed as arguments
    public UserManager(ApiService apiService, UserStore userStore) {
        this.apiService = apiService;
        this.userStore = userStore;
    }

    void registerUser() {/*  */}

}

class RegisterActivity extends Activity {

    private UserManager userManager;

    @Override
    protected void onCreate(Bundle b) {
        super.onCreate(b);
        ApiService api = ApiService.getInstance();
        UserStore store = UserStore.getInstance();
        
        this.userManager = new UserManager(api, store);
    }

    public void onRegisterClick(View v) {
        userManager.registerUser();
    }

}

如今在類似的狀況下 - 咱們改變它其中一個依賴的實現方式 - 咱們不須要修改UserManager源代碼。全部它的依賴都是從外面提供的,因此咱們惟一一個須要修改的地方就是咱們構造的UserStore對象。模塊化

因此使用依賴注入的優點是什麼呢?

構造/使用 的分離

當咱們構造類的實例 - 一般這些對象會在其它的地方被使用到,多虧這個方法讓咱們的代碼更加模塊化 - 全部的依賴均可以被很簡單地替換掉(只要他們實現了相同的接口),而且不會與咱們應用的邏輯產生衝突。想要改變DatabaseUserStoreSharedPrefsUserStore ?好的,只須要關心公開的API(與DatabaseUserStore相同的)或者實現相同的接口。

單元測試(Unit testing)

真正的單元測試假設一個類是能夠徹底被隔離進行測試的 - 不須要了解它的相關依賴。在實踐中,基於咱們的UserManager類,這裏有一個咱們應該編寫的單元測試的例子:

public class UserManagerTests {

    UserManager userManager;

    @Mock
    ApiService apiServiceMock;
    @Mock
    UserStore userStoreMock;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        userManager = new UserManager(apiServiceMock, userStoreMock);
    }

    @After
    public void tearDown() {
    }

    @Test
    public void testSomething() {
        //Test our userManager here - all its dependencies are satisfied
    }
}

它可能只能使用DI - 多虧UserManager是徹底獨立於UserStoreApiService實現的。咱們能夠提供這些類的mock(簡單地說 - mocks是一些擁有相同公開API的類,它在方法中不作任何事情而且/或者返回咱們指望的值),而後在一個與所依賴的真實實現分離出來的環境下進行對UserManager的測試。

獨立/並行開發

多虧模塊化的代碼(UserStore能夠從UserManager中獨立出來進行實現),它也能夠很是方便在程序員間進行代碼的分離。只須要UserStore相關的接口被每一個人知道(尤爲是在UserManager中使用到的UserStore中的公開方法)便可。剩下的(實現,邏輯)能夠經過單元測試來測試。

依賴注入框架

依賴注入除了這些優勢以外還有一些缺點。其中一個缺點是會產生很大的模版代碼。想象一個簡單的LoginActivity類,它在MVP(model-view-presenter)模式中被實現。這個類看起來就像這樣:

惟一有問題的部分代碼就是LoginActivityPresenter的初始化,以下:

public class LoginActivity extends AppCompatActivity {

    LoginActivityPresenter presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        OkHttpClient okHttpClient = new OkHttpClient();
        RestAdapter.Builder builder = new RestAdapter.Builder();
        builder.setClient(new OkClient(okHttpClient));
        RestAdapter restAdapter = builder.build();
        ApiService apiService = restAdapter.create(ApiService.class);
        UserManager userManager = UserManager.getInstance(apiService);
        
        UserDataStore userDataStore = UserDataStore.getInstance(
                getSharedPreferences("prefs", MODE_PRIVATE)
        );

        //Presenter is initialized here
        presenter = new LoginActivityPresenter(this, userManager, userDataStore);
    }
}

它看起來不太友好,不是嗎?

這就是DI框架須要解決的問題。相同功能的代碼看起來就像這樣:

public class LoginActivity extends AppCompatActivity {

    @Inject
    LoginActivityPresenter presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        //Satisfy all dependencies requested by @Inject annotation
        getDependenciesGraph().inject(this);
    }
}

簡單多了,對吧?固然DI框架沒有地方能夠獲取到對象 - 他們仍然須要在咱們代碼的某個地方進行初始化和配置。可是對象構建從使用中分離出來了(實質上這是DI模式的準則)。DI框架關心怎麼樣去把它們聯繫在一塊兒(怎麼在對象被須要時分配給它們)。

未完待續

我上面全部描述的東西都是使用Dagger 2的簡單的背景 - 用於Android和Java開發的依賴注入框架。在下一章我將嘗試講解全部Dagger 2的API。若是你等不急能夠嘗試個人Github client example,它創建在Dagger 2之上而且會用在個人展現中。一個小提示 - @Module@Component就是構建/提供對象的地方。@Inject是咱們對象使用到的地方。

More detailed description - soon.

參考

做者

Miroslaw Stanek

Head of Mobile Development @ Azimo


[Android]使用Dagger 2依賴注入 - DI介紹(翻譯):

http://www.cnblogs.com/tiantianbyconan/p/5092083.html


[Android]使用Dagger 2依賴注入 - API(翻譯):

http://www.cnblogs.com/tiantianbyconan/p/5092525.html


[Android]使用Dagger 2依賴注入 - 自定義Scope(翻譯):

http://www.cnblogs.com/tiantianbyconan/p/5095426.html


[Android]使用Dagger 2依賴注入 - 圖表建立的性能(翻譯):

http://www.cnblogs.com/tiantianbyconan/p/5098943.html


[Android]Dagger2Metrics - 測量DI圖表初始化的性能(翻譯):

http://www.cnblogs.com/tiantianbyconan/p/5193437.html


[Android]使用Dagger 2進行依賴注入 - Producers(翻譯):

http://www.cnblogs.com/tiantianbyconan/p/6234811.html


[Android]在Dagger 2中使用RxJava來進行異步注入(翻譯):

http://www.cnblogs.com/tiantianbyconan/p/6236646.html


[Android]使用Dagger 2來構建UserScope(翻譯):

http://www.cnblogs.com/tiantianbyconan/p/6237731.html


[Android]在Dagger 2中Activities和Subcomponents的多綁定(翻譯):

http://www.cnblogs.com/tiantianbyconan/p/6266442.html

相關文章
相關標籤/搜索