美文网首页Android开发Android开发Android开发经验谈
Dagger2 简单入门三部曲(一)——是什么?

Dagger2 简单入门三部曲(一)——是什么?

作者: d74f37143a31 | 来源:发表于2018-11-27 22:07 被阅读12次

    Dagger2 简单入门三部曲(一)——是什么?
    Dagger2 简单入门三部曲(二)——为什么使用?(进行中)
    Dagger2 简单入门三部曲(三)——怎么使用?(进行中)

    Github 的介绍是:A fast dependency injector for Android and Java。(Android和Java的快速依赖注入器)

    Dagger2 Github 地址

    通过上边了解到依赖注入这个词,在AndroidJava中什么是依赖注入呢?

    依赖注入是什么?

    在软件工程领域,依赖注入(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。

    相关文章

      网友评论

        本文标题:Dagger2 简单入门三部曲(一)——是什么?

        本文链接:https://www.haomeiwen.com/subject/edinqqtx.html