刚开始学习软件工程的时候,我们经常会碰到像这样的事情:
软件应该符合 solid 原则。
但这句话实际是什么意思?让我们看看 solid 中每个字母在架构里所代表的重要含义,例如:
<a href="https://en.wikipedia.org/wiki/single_responsibility_principle" target="_blank">s - 单职责原则</a>
<a href="https://en.wikipedia.org/wiki/open/closed_principle" target="_blank">o - 开闭原则</a>
<a href="http://liskov_substitution_principle/" target="_blank">l - liskov 替换原则</a>
<a href="https://en.wikipedia.org/wiki/interface_segregation_principle" target="_blank">i - 接口分离原则</a>
简单来说,我们需要提供一个类,这个类有它所需要的所有对象,以便实现其功能。
<a target="_blank"></a>
依赖注入听起来像是描述非常复杂的东西的一个术语,但实际上它很简单,看下面这个例子你就明白了:
<code>class nodependencyinjection {</code>
<code>private dependency d;</code>
<code></code>
<code>public nodependencyinjection() {</code>
<code>d = new dependency();</code>
<code>}</code>
<code>class dependencyinjection {</code>
<code>public dependencyinjection(dependency d) {</code>
<code>this.d = d;</code>
正如我们所见,第一种情况是我们在构造器里创建了依赖对象,但在第二种情况下,它作为参数被传递给构造器,这就是我们所说的依赖注入dependency injection。这样做是为了让我们所写的类不依靠特定依赖关系的实现,却能直接使用它。
参数传递的目标是构造器,我们就称之为构造器依赖注入;或者是某个方法,就称之为方法依赖注入:
<code>class example {</code>
<code>private constructordependency cd;</code>
<code>private methoddependency md;</code>
<code>example(constructordependency cd) {</code>
<code>this.cd = cd; //constructor dependency injection</code>
<code>public setmethoddependency(methoddependency md) {</code>
<code>this.md = md; //method dependency injection</code>
安装 dagger 并不难,但需要导入 <code>android-apt</code> 插件,通过向项目的根目录下的 <code>build.gradle</code> 文件中添加它的依赖关系:
<code>buildscript{</code>
<code>...</code>
<code>dependencies{</code>
<code>classpath ‘com.neenbedankt.gradle.plugins:android-apt:1.8’</code>
然后,我们需要将 <code>android-apt</code> 插件应用到项目 <code>build.gradle</code> 文件,放在文件顶部 android application 那一句的下一行:
<code>apply plugin: ‘com.neenbedankt.android-apt’</code>
这个时候,我们只用添加依赖关系,然后就能使用库及其注解annotation了:
<code>compile ‘com.google.dagger:dagger:2.6’</code>
<code>apt ‘com.google.dagger:dagger-compiler:2.6’</code>
<code>provided ‘javax.annotation:jsr250-api:1.0’</code>
要注入依赖,首先需要告诉框架我们能提供什么(比如说上下文)以及特定的对象应该怎样创建。为了完成注入,我们用 <code>@module</code> 注释对一个特殊的类进行了注解(这样 dagger 就能识别它了),寻找<code>@provide</code> 注解的方法,生成图表,能够返回我们所请求的对象。
看下面的例子,这里我们创建了一个模块,它会返回给我们 <code>connectivitymanager</code>,所以我们要把<code>context</code> 对象传给这个模块的构造器。
<code>@module</code>
<code>public class applicationmodule {</code>
<code>private final context context;</code>
<code>public applicationmodule(context context) {</code>
<code>this.context = context;</code>
<code>@provides @singleton</code>
<code>public context providescontext() {</code>
<code>return context;</code>
<code>public connectivitymanager providesconnectivitymanager(context context) {</code>
<code>return (connectivitymanager) context.getsystemservice(context.connectivity_service);</code>
dagger 中十分有意思的一点是简单地注解一个方法来提供一个单例(singleton),就能处理所有从 java 中继承过来的问题。
当我们有一个模块的时候,我们需要告诉 dagger 想把依赖注入到哪里:我们在一个组件component里完成依赖注入,这是一个我们特别创建的特殊注解接口。我们在这个接口里创造不同的方法,而接口的参数是我们想注入依赖关系的类。
下面给出一个例子并告诉 dagger 我们想要 <code>mainactivity</code> 类能够接受 <code>connectivitymanager</code>(或者在图表里的其它依赖对象)。我们只要做类似以下的事:
<code>@singleton</code>
<code>@component(modules = {applicationmodule.class})</code>
<code>public interface applicationcomponent {</code>
<code>void inject(mainactivity activity);</code>
正如我们所见,@component 注解有几个参数,一个是所支持的模块的数组,代表它能提供的依赖。这里既可以是 <code>context</code> 也可以是 <code>connectivitymanager</code>,因为它们在 <code>applicationmodule</code> 类中有声明。
这时,我们要做的是尽快创建组件(比如在应用的 <code>oncreate</code> 阶段)并返回它,那么类就能用它来注入依赖了:
为了让框架自动生成 <code>daggerapplicationcomponent</code>,我们需要构建项目以便 dagger 能够扫描我们的代码,并生成我们需要的部分。
在 <code>mainactivity</code> 里,我们要做的两件事是用 <code>@inject</code> 注解符对想要注入的属性进行注解,调用我们在 <code>applicationcomponent</code> 接口中声明的方法(请注意后面一部分会因我们使用的注入类型的不同而变化,但这里简单起见我们不去管它),然后依赖就被注入了,我们就能自由使用他们:
<code>public class mainactivity extends appcompatactivity {</code>
<code>@inject</code>
<code>connectivitymanager manager;</code>
<code>@override</code>
<code>protected void oncreate(bundle savedinstancestate) {</code>
<code>((app) getapplication()).getcomponent().inject(this);</code>
当然了,我们可以手动注入依赖,管理所有不同的对象,但 dagger 消除了很多比如模板这样的“噪声”,给我们提供有用的附加品(比如 <code>singleton</code>),而仅用 java 处理将会很糟糕。
原文发布时间为:2017-12-27
本文来自云栖社区合作伙伴“linux中国”