Dagger2 简单入门三部曲(一)——是什么?
Dagger2 简单入门三部曲(二)——为什么使用?(进行中)
Dagger2 简单入门三部曲(三)——怎么使用?(进行中)
Github 的介绍是:A fast dependency injector for Android and Java。(Android和Java的快速依赖注入器)
通过上边了解到依赖注入这个词
,在Android
和Java
中什么是依赖注入
呢?
依赖注入是什么?
在软件工程领域,依赖注入(Dependency Injection)是用于实现控制反转(Inversion of Control)的最常见的方式之一。
上面提到控制反转
这个词,那么什么是控制反转
呢?
控制反转是什么?
百度百科 是这么介绍的:
控制反转(
Inversion of Control
,缩写为IoC
),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection
,简称DI
),还有一种方式叫“依赖查找”(Dependency Lookup
)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
民间通俗理解:
就是你一个类里面需要用到很多个成员变量,传统的写法,你要用这些成员变量,那么你就
new
出来用呗~~
IoC
的原则是:NO
,我们不要new
,这样耦合度太高;你配置个xml
文件,里面标明哪个类,里面用了哪些成员变量,等待加载这个类的时候,我帮你注入(new
)进去;
这里又有个问题,解耦解的谁和谁的耦?
下面来看实现一个导演名来搜索电影的代码:
public class MovieLister {
private MovieFinder finder;
public MovieLister() {
// MovieFinderImpl 实现里具体的查找所有电影方法
finder = new MovieFinderImpl();
}
/**
* 根据导演名来搜索电影,返回电影集合
* @param arg 导演名
*/
public Movie[] moviesDirectedBy(String arg) {
// 获取所有电影
List allMovies = finder.findAll();
for (Iterator it = allMovies.iterator(); it.hasNext();) {
Movie movie = (Movie) it.next();
// 移除不是该导演的电影
if (!movie.getDirector().equals(arg)) it.remove();
}
return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
}
...
}
/**
* 抽象实现接口
*/
public interface MovieFinder {
List findAll();
}
以上代码看起来还是很美观的,但是
当我们希望修改 finder
,将finder
替换为一种新的实现时(比如为MovieFinder
增加一个参数表明Movie
数据的来源是哪个数据库),我们不仅需要修改MovieFinderImpl
类,还需要修改我们MovieLister
中创建MovieFinderImpl
的代码
这就是依赖注入要处理的耦合。这种在MovieLister
中创建MovieFinderImpl
的方式,使得MovieLister
不仅仅依赖于MovieFinder
这个接口,它还依赖于MovieListImpl
这个实现。 这种在一个类中直接创建另一个类的对象的代码, 是一种导致耦合的方式。
那么我们如何去实现依赖注入从而达到解耦呢?
常用的有三种方式实现
- 构造函数 注入(Contructor Injection)
继续拿上面的代码来分析,通过构造函数注入可以让MovieLister
就只依赖于我们定义的MovieFinder
接口,而不依赖于MovieFinder
的实现了,这就减少了一个耦合。实现的代码如下:
public class MovieLister {
private MovieFinder finder;
public MovieLister(MovieFinder finder) {
this.finder = finder;
}
...
}
- setter 注入
下面的实现也是减去了MovieFinderImpl
的耦合
public class MovieLister {
private MovieFinder finder;
...
public void setFinder(MovieFinder finder) {
this.finder = finder;
}
}
- 接口 注入
首先要创建一个注入使用的接口:
public interface InjectFinder {
void injectFinder(MovieFinder finder);
}
之后,我们让MovieLister
实现这个接口
class MovieLister implements InjectFinder {
private MovieFinder finder;
...
public void injectFinder(MovieFinder finder) {
this.finder = finder;
}
...
}
这里贴出利用接口注入实现解耦后的完整代码:
// MovieFinder
public interface MovieFinder {
List findAll();
}
// MovieFinderImpl 具体实现
public class MovieFinderImpl implements MovieFinder {
private static final String TAG = "MovieFinderImpl";
@Override
public List findAll() {
Log.e(TAG, "findAll: 查找所有电影");
return new ArrayList();
}
}
先定义一个接口
public interface InjectFinder {
void injectFinder(MovieFinder finder);
}
实现该接口
public class MovieLister implements InjectFinder{
private static final String TAG = "MovieLister";
private MovieFinder finder;
/**
* 根据导演名来搜索电影,返回电影集合
* @param arg 导演名
*/
public Movie[] moviesDirectedBy(String arg) {
// 获取所有电影
List allMovies = finder.findAll();
// 简单打印语句
Log.e(TAG, "moviesDirectedBy: 移除不是"+arg+"导演的电影" );
return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
}
@Override
public void injectFinder(MovieFinder finder) {
this.finder = finder;
}
}
调用:
MovieFinder movieFinder = new MovieFinderImpl();
MovieLister movieLister = new MovieLister();
// 这里通过接口注入
movieLister.injectFinder(movieFinder);
movieLister.moviesDirectedBy("张艺谋");
不出意外,运行之后会得到如下的显示结果:
这是输出的结果
综上所述
Dagger2
是一个依赖注入框架,用于实现控制反转的一种方式,主要是为了降低代码之间的耦合度。常见的依赖注入解耦方式有:构造函数注入、setter 注入、接口注入。
控制反转的实现还有另一种方式是
依赖查找
,这里暂时不深入研究了。
文章到这里就结束了,下篇文章介绍,为什么使用 Dagger2。
网友评论