一、入门:依赖注入

作为一种全新的设计模式理念,“依赖注入”这个词汇在软件设计开发中已经是越来越耳熟能详了,而各种流行于开源社区的“依赖注入框架”,也越来越多的被当作软件工程开发过程中使用的基础框架。这一章我们主要介绍什么是依赖注入、它的来源是什么、以及能给我们带来什么样的好处。

1.     “依赖”的概念

要了解依赖注入,我们首先需要了解什么是“依赖”。从现实世界的观点来看,“依赖”即某个实体对象为了完成某项功能,必须要依托另外一些实体对象,那么这些被依托的实体对象即被称为“依赖”(Dependency),而依托其它“依赖”从而完成某项功能的对象,往往被称作“依赖者”(Dependent)。看似有些晦涩难懂,但用我们平常使用的Java语言来讲,其实很简单,所谓“依赖”,用最浅显的话说,就是我们平常写一个Java类中所定义的成员变量。(注:严格来说,还有把方法参数作为“依赖”的情况,我们暂不讨论此例)

看一个很常见的场景的例子:某储户需要到银行去办理一笔取款业务。在这个场景中,该储户即为一个“依赖者”;那么其为了完成取款业务,则需要依托很多其它的实体对象,为简单起见,我们假设该储户仅需要一张存折和附近的一所银行,此处存折和银行则为“依赖”。翻译成Java语言去描述,则可写出如下的代码。

public class Depositor {

private Bank bank; // 银行是其依赖

private DepositBook depositBook; // 存折是其依赖

public Cash withDraw(BigDecimal amount) { // 依托上面的依赖完成取款业务

return bank.withDraw(depositBook, amount);

}

}

“依赖注入”的概念及其实践来源于Java的开源社区,但是这种理念亦可以应用到其它面向对象、并带有Garbage Collection和反射机制的静态语言当中,例如C#。

2.     传统的组件耦合方式及其带来的问题

我们都知道,一个对象(依赖者)当中调用另外一个对象(依赖)的API,即组件间的耦合是面向对象语言开发过程中必然要遇到的问题。拿我们刚才的例子来说,储户类调用银行类就可以看作是储户与银行两个组件在相互耦合。但是刚才的那个例子是不能被主程序直接运行的,因为我们的bank依赖并没有被初始化,所以如果调用到了Depositor#withDraw则会出现NullPointerException(NPE)异常。

public class DepositMain {

public void run() {

Depositor depositor = new Depositor();

depositor.withDraw(new BigDecimal(10000)); // NPE异常!

}

}

因此我们需要想办法得到一个“组装”好的Depositor类的对象。在依赖注入设计模式出现以前,通常有下面几种组件的组装方法,我们依次来讨论一下。

2.1.    手工组装模式

一种常见的组件耦合方式就是我们经常使用的“new”,即通过依赖类的构造方法new出一个新的对象作为依赖者类的初始化状态。

继续我们刚才的例子,在主程序能够new出依赖之前,首先我们要实现一个工商银行的银行类,以及一个工商银行的存折类。

public class BankICBC implements Bank {

public BankICBC(String address, Integer bankNo) {

this.address = address; // 银行地址

this.bankNo = bankNo;  // 银行营业网点编号

}

private String address;

private Integer bankNo;

@Override

public Cash withDraw(DepositBook depositBook, BigDecimal amount) {

// ……

}

}

public class DepositBookICBC implements DepositBook {

private String bookID;  // 存折账号

private String bookType; // 存折种类

private String currecyType;  // 货币种类

public DepositBookICBC(String bookID, String bookType, String currecyType) {

this.bookID = bookID;

this.bookType = bookType;

this.currecyType = currecyType;

}

// ……

}

之后我们便可以在Depositor类中利用这些实现类初始化出需要的依赖对象后,刚才的DepositMain就可以正常运行了。

public class Depositor {

private Bank bank;

private DepositBook depositBook;

public Cash withDraw(BigDecimal amount) {

bank = new BankICBC("Tianjin", 100); // 初始化依赖

depositBook = new DepositBookICBC("62202", "current", "CNY"); // 初始化依赖

return bank.withDraw(depositBook, amount);

}

}

这种手工new的组装方式,虽然是Java平台程序开发中最基本的方式,但是其会带给我们在开发、维护以及测试等方面带来极大的困扰。

l        还以刚才的取款场景为例,开发过程中,对于实现储户取款这个场景(Depositor)的开发者来说,需要关心的事情只是储户取了多少钱,而不应该为了调用取款的API而费尽心思地去创建Bank和DepositBook对象。我们这个例子是非常简单的,仅仅是为了说明方便所以将依赖的构造函数的参数设定为及其简单的Java基础类型,试想在现实的开发中,Bank和DepositBook依赖自身还将会有依赖,依赖中又有依赖,如果是这样一个极其复杂的依赖关系图(DependencyGraph),对于开发人员来讲构建组件将会是非常痛苦的一件事情!并且,如果在依赖关系图中的某一层中涉及到了诸如DataSource连接、硬件连接这样的依赖对象,开发人员一定会抱怨“这些对象与我在开发的功能完全没有关系”!

l        从代码维护的角度看,过多的用构造方法new出对象这种方式,对于代码变更的维护的成本也是巨大的。例如,我们的BankICBC实现类的构造参数发生了变更,比如需要追加一个“网点类型(分理处/支行/分行)”这样的参数,那么我们的代码中所有调用到BankICBC的地方都需要发生相应的修改及对应的回归测试!

l        最后我们谈到的一点,也是软件开发过程中极其关键的一点,即给单元测试带来的不便。例如在实际的单元测试过程中,“工商银行”类由于牵扯到实际环境以及难以构建复杂依赖图等原因我们没有办法直接使用,而想要自行在测试代码中实现一个Mock类来代替实际的“工商银行”类,比如MockBank,我们会发现这个MockBank类没有办法方便地替入到实际的Depositor#withDraw代码中去。单元测试往往是软件工程中自动化程度最高,回归测试成本最低的测试手段,如果没有良好的单元测试体系,软件工程的维护等是难以方便的运行的。

转载于:https://www.cnblogs.com/Free-Thinker/p/4173252.html

依赖注入及AOP简述(一)——“依赖”的概念 .相关推荐

  1. 依赖注入及AOP简述(五)——依赖注入的方式 .

    二.依赖注入的应用模式 前面我们了解了依赖注入的基本概念,也对一些依赖注入框架进行了简单的介绍,这一章我们主要来讨论作为开发者如何利用依赖注入框架来实现依赖注入的设计思想. 1.     依赖注入的方 ...

  2. 依赖注入及AOP简述(六)——字符串请求模式 .

    2.     依赖注入对象的请求模式 前一节我们讨论了关于声明注入点的几种方法,这一节主要来介绍在注入点上如何定位到所需要的标识符的话题.基本上,我们可以用字符串为标识符来请求依赖对象.或者用全类名( ...

  3. JavaEE开发之Spring中的依赖注入与AOP编程

    上篇博客我们系统的聊了<JavaEE开发之基于Eclipse的环境搭建以及Maven Web App的创建>,并在之前的博客中我们聊了依赖注入的相关东西,并且使用Objective-C的R ...

  4. 第七节:WebApi与Unity整合进行依赖注入和AOP的实现

    一. IOC和DI 1. 通过Nuget引入Unity程序集. PS:[版本:5.8.6] 2. 新建DIFactory类,用来读取Unity的配置文件并创建Unity容器,需要注意的是DIFacto ...

  5. ASP.NET Core中的依赖注入(2):依赖注入(DI)

    IoC主要体现了这样一种设计思想:通过将一组通用流程的控制从应用转移到框架之中以实现对流程的复用,同时采用"好莱坞原则"是应用程序以被动的方式实现对流程的定制.我们可以采用若干设计 ...

  6. php程序设计依赖注入_PHP控制反转和依赖注入

    [TOC] PHP和依赖注入 理论知识 要了解控制反转( Inversion of Control ), 我觉得有必要先了解软件设计的一个重要思想:依赖倒置原则(Dependency Inversio ...

  7. java 什么时候依赖注入_玩框架java依赖注入 – 何时使用单例

    So I am wondering, should I be using singleton objects as the examples seem to imply? If this is the ...

  8. 框架依赖注入和普通依赖注入_角服务和依赖注入解释

    框架依赖注入和普通依赖注入 服务和喷油器 (Services and Injectors) Components are responsible for the data that renders i ...

  9. php 依赖注入的写法,php的依赖注入详解

    本篇文章讲述了PHP的依赖注入,对于php依赖注入不太了解的同学但是有点感兴趣的那么就更要看看本篇文章咯,废话不多说了,我们直接来看看php的依赖注入吧! 依赖注入 理解:是一种允许我们从硬编码的依赖 ...

最新文章

  1. matlab语言unique,Matlab的unique函数的C++实现
  2. 100个必会的python脚本-Python 经典算法100及解析(小结)
  3. spring:如何用代码动态向容器中添加或移除Bean ?
  4. python面对对象编程------3:写集合类的三种方法
  5. Java黑皮书课后题第9章:**9.12(几何:交点)假设两条线段相交。第一条线段的两个端点是(x1, y1)和(x2, y2),第二条线段的两个端点是(x3, y3)和(x4, y4)
  6. 51单片机电子制作------篮球比赛计分器
  7. ROS系统学习9---节点间的内存共享(中级篇)---图像收发
  8. python:文件处理之TXT
  9. 容斥原理与Mobius函数
  10. sql compare mysql版本_SQL Compare 13免费版
  11. 华为手机wifi不显示连接到服务器,华为手机中无法连接WIFI处理方法
  12. jeffery0207博客导航
  13. Spring Cloud Gateway编码实现任意地址跳转
  14. Automatic Panoramic Image Stitching using Invariant Features笔记
  15. 北语计算机基础知识作业1,【图】- 北京语言大学20秋《计算机基础》作业1 - 昆山经济开发区其他教育培训 - 昆山百姓网...
  16. MotoSimEG-VRC软件:多机器人信号交互与PLC功能
  17. Flink 网络流控和反压剖析详解
  18. 从头搭建一个“微博”有多难
  19. window 10获取当前语言c,如何显示“获取windows10应用”,分享我的经验
  20. 2018年IT名企校招日程表汇总

热门文章

  1. 【聊透SpringMVC】java找不到指定文件
  2. 【原理+实战+视频+源码】java更新无法下载所需安装文件
  3. python【数据结构与算法】01背包问题(附例题)
  4. python【蓝桥杯vip练习题库】ALGO-231多阶乘计算
  5. Confusion matrix
  6. JavaIO(输入输出)——字节流读写文件
  7. mysql数据库批量编码_MySQL批量修改数据库的编码类型
  8. finalshell Linux 传输文件 xftp
  9. 郑州网络推广教你如何“悄悄”做网站SEO,惊艳竞争对手?
  10. 网站面临改版!在修改标题后该如何快速提升排名?