注:
- 1. 代码中的 //<= 表示新加的、修改的等需要重点关注的代码
- 2. Class#method表示一个类的instance method,比如 LoginPresenter#login 表示 LoginPresenter的login(非静态)方法。
问题
在前一篇文章中,我们讲述了依赖注入的概念,以及依赖注入对单元测试极其关键的重要性和必要性。在那篇文章的结尾,我们遇到了一个问题,那就是如果不使用DI框架,而全部采用手工来做DI的话,那么所有的Dependency都需要在最上层的client来生成,这可不是件好事情。继续用我们前面的例子来具体说明一下。
假设有一个登录界面,LoginActivity
,他有一个LoginPresenter
,LoginPresenter
用到了UserManager
和PasswordValidator
,为了让问题变得更明显一点,我们假设UserManager
用到SharedPreference
(用来存储一些用户的基本设置等)和UserApiService
,而UserApiService
又需要由Retrofit
创建,而Retrofit
又用到OkHttpClient
(比如说你要自己控制timeout、cache等东西)。
应用DI模式,UserManager的设计如下:
1 2 3 4 5 6 7 8 9 10 11 |
public class UserManager { private final SharedPreferences mPref; private final UserApiService mRestAdapter; public UserManager(SharedPreferences preferences, UserApiService userApiService) { this.mPref = preferences; this.mRestAdapter = userApiService; } /**Other code*/ } |
LoginPresenter的设计如下:
1 2 3 4 5 6 7 8 9 10 11 |
public class LoginPresenter { private final UserManager mUserManager; private final PasswordValidator mPasswordValidator; public LoginPresenter(UserManager userManager, PasswordValidator passwordValidator) { this.mUserManager = userManager; this.mPasswordValidator = passwordValidator; } /**Other code*/ } |
在这种情况下,最终的client LoginActivity里面要new一个presenter,需要做的事情如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class LoginActivity extends AppCompatActivity { private LoginPresenter mLoginPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); OkHttpClient okhttpClient = new OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .build(); Retrofit retrofit = new Retrofit.Builder() .client(okhttpClient) .baseUrl("https://api.github.com") .build(); UserApiService userApiService = retrofit.create(UserApiService.class); SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); UserManager userManager = new UserManager(preferences, userApiService); PasswordValidator passwordValidator = new PasswordValidator(); mLoginPresenter = new LoginPresenter(userManager, passwordValidator); } } |
这个也太夸张了,LoginActivity
所需要的,不过是一个LoginPresenter
而已,然而它却需要知道LoginPresenter
的Dependency是什么,LoginPresenter
的Dependency的Dependency又是什么,然后new一堆东西出来。而且可以预见的是,这个app的其他地方也需要这里的OkHttpClient
、Retrofit
、SharedPreference
、UserManager
等等dependency,因此也需要new这些东西出来,造成大量的代码重复,和不必要的object instance生成。然而如前所述,我们又必须用到DI模式,这个怎么办呢?
想想,如果能达到这样的效果,那该有多好:我们只需要在一个类似于dependency工厂的地方统一生产这些dependency,以及这些dependency的dependency。所有需要用到这些Dependency的client都从这个工厂里面去获取。而且更妙的是,一个client(比如说LoginActivity
)只需要知道它直接用到的Dependency(LoginPresenter
),而不需要知道它的Dependency(LoginPresenter
)又用到哪些Dependency(UserManager
和PasswordValidator
)。系统自动识别出这个依赖关系,从工厂里面把需要的Dependency找到,然后把这个client所需要的Dependency创建出来。
有这样一个东西,帮我们实现这个效果吗?相信聪明的你已经猜到了,回答是肯定的,它就是我们今天要介绍的dagger2。
解药:Dagger2
在dagger2里面,负责生产这些Dependency的统一工厂叫做 Module ,所有的client最终是要从module里面获取Dependency的,然而他们不是直接向module要的,而是有一个专门的“工厂管理员”,负责接收client的要求,然后到Module里面去找到相应的Dependency,提供给client们。这个“工厂管理员”叫做 Component。基本上,这是dagger2里面最重要的两个概念。
下面,我们来看看这两个概念,对应到代码里面,是怎么样的。
生产Dependency的工厂:Module
首先是Module,一个Module对应到代码里面就是一个类,只不过这个类需要用dagger2里面的一个annotation @Module
来标注一下,来表示这是一个Module,而不是一个普通的类。我们说Module是生产Dependency的地方,对应到代码里面就是Module里面有很多方法,这些方法做的事情就是创建Dependency。用上面的例子中的Dependency来说明:
1 2 3 4 5 6 7 8 9 10 11 12 on-striped-num" data-line="crayon-5812bba225b08205486941-8">8 9 10 11 12 oginPresenter的login(非静态)方法。
问题在前一篇文章中,我们讲述了依赖注入的概念,以及依赖注入对单元测试极其关键的重要性和必要性。在那篇文章的结尾,我们遇到了一个问题,那就是如果不使用DI框架,而全部采用手工来做DI的话,那么所有的Dependency都需要在最上层的client来生成,这可不是件好事情。继续用我们前面的例子来具体说明一下。 假设有一个登录界面, 应用DI模式,UserManager的设计如下:
LoginPresenter的设计如下:
在这种情况下,最终的client LoginActivity里面要new一个presenter,需要做的事情如下:
这个也太夸张了, 想想,如果能达到这样的效果,那该有多好:我们只需要在一个类似于dependency工厂的地方统一生产这些dependency,以及这些dependency的dependency。所有需要用到这些Dependency的client都从这个工厂里面去获取。而且更妙的是,一个client(比如说 有这样一个东西,帮我们实现这个效果吗?相信聪明的你已经猜到了,回答是肯定的,它就是我们今天要介绍的dagger2。 解药:Dagger2在dagger2里面,负责生产这些Dependency的统一工厂叫做 Module ,所有的client最终是要从module里面获取Dependency的,然而他们不是直接向module要的,而是有一个专门的“工厂管理员”,负责接收client的要求,然后到Module里面去找到相应的Dependency,提供给client们。这个“工厂管理员”叫做 Component。基本上,这是dagger2里面最重要的两个概念。 下面,我们来看看这两个概念,对应到代码里面,是怎么样的。 生产Dependency的工厂:Module首先是Module,一个Module对应到代码里面就是一个类,只不过这个类需要用dagger2里面的一个annotation
|