控制反转(Inversion of Control)之我的理解
关于控制反转(Inversion of Control),在具体实现上也有许多其它的叫法,如依赖倒置(Dependency Inversion Principles, DIP)、依赖注入(Dependency Injection)等等,现在自己就本人的理解,来说一下这里的反转及倒置的讲究。
就总的原则来说,控制反转(依赖倒置)是:
高层模块不应该依赖于低层模块,二者都要依赖于抽象
抽象不应该依赖于具体,具体应该依赖于抽象。
从现实社会生活中,我们知道:官职越大的人,负责的工作越抽象,官职越低的人,负责的工作越具体;所以说,上面动动嘴皮子,下面跑断腿。也就是说,正常状态下,应该是高层调用(控制)低层办理具体的事务,我们估且说这是正置吧;如果低层调用(控制)高层进行工作,这种情况可以说是倒置了。
软件设计中,确实存在有正置和倒置。正置是结构化设计时的情况,自上而下,由高层调用低层完成软件设计,低层的具体工作向高层提供服务,而且IT中许多设计思想也是正置的,比如计算机网络的七层(或五层)架构,物理层向上层数据链路层提供服务(下层向上层提供服务,上层调用或控制或依赖下层),数据链路层向上层网络层提供服务,等等。
但在面向对象的设计中,为了降低模块间的耦合,实际低耦合,高内聚的总原则,控制反转就成为面向对象设计的主要原则。
看下例:
public class EmailService
{
public void SendMessage()
{....}
} public class NotificationSystem
{
private EmailServie svc;
public NotificationSystem()
{
svc = new EmailService();
} public void InterestingEventHappened()
{
svc.SendMessage();
}
}
这是典型的正置,类EmailService属于具体类(低层模块),发出邮件;而NotificationSystem类则是调用类(高层模块),它调用(控制)具体类EmailService中的具体方法完成任务,这在面向对象设计中,是一种紧耦合。
这种紧耦合可能会造成如下问题:
1、当两个模块其中之一产生修改时,另外一个模块就会受到影响。如果多个模块紧耦合,这个影响就有可能造成软件系统修改量巨大,如果是封装出售的商业模块,对购买者今后的平滑升级与维护将造成极大困难。
2、如果这时NotificationSystem要发出的消息不是电邮,而是短信或者存到数据库中以后再看,这个类就需要再进行修改。
为解决这个问题,就需要把紧耦合变为松耦合,办法就是:加入一个抽象层,大家都依赖于抽象层,因为抽象层是最不容易变化的,从某种程序上来讲,设计完成之后,抽象层应该永远不变,如果需要,可以再添加其它抽象层。
这个抽象层可以是接口(Interface)或者抽象类(Abstract Class),但一般建议使用接口完成。
public interface IMessagingService
{
void SendMessage();
}
public class EmailService : IMessagingService
{
public void SendMessage()
{....}
} public class NotificationSystem
{
private IMessagingService svc;
public NotificationSystem()
{
svc = new EmailService();
} public void InterestingEventHappened()
{
svc.SendMessage();
}
}
看上面的代码,添加了一个接口IMessagingService。然后高层模块NotificationSytem依赖于抽象的接口,低层模块EmailService实现这个抽象接口内的方法定义(或称虚方法、虚函数);事实是两者都依赖于这个抽象接口。低层模块EmailService通过实现接口方法定义完成对它的依赖(即EmailService : IMessagingService),而高层模块NotificationSystem则通过声明接口IMessagingService(抽象层)实现了对它的调用(依赖),而这个调用实际是调用的更高层,因为抽象层是最高层,这种调用,就是控制反转或者依赖倒置。实际调用的是它的具体实现,而这个具体实现由EmailService中的SendMessage方法完成。
这里只是谈了控制反转或者依赖倒置的总原则。对于依赖倒置的具体办法,其它文章再谈。
----------
因为还有一种情况没有解决,如果现在要加入发短信的功能,应该有类似下面的代码
public class SmsService : IMessagingService
{
public void SendMessage()
{....}
}
但只加入下面的代码,还没有完成发短信的功能,需要修改NotificationSystem类中构造函数的实现了,它写的是静态的实例化EmailService对象。因此解决办法应该是:在构造函数中(或者实现方法InterestingEventHappened()中)加入传递参数,这个传递参数就是具体的低层模块类(或具体实现模块类)实例化的对象,这样就不需要修改主程序代码,实现了对修改封闭,对扩展开放的OO设计原则。
控制反转(Inversion of Control)之我的理解的更多相关文章
- 控制反转Inversion of Control (IoC) 与 依赖注入Dependency Injection (DI)
控制反转和依赖注入 控制反转和依赖注入是两个密不可分的方法用来分离你应用程序中的依赖性.控制反转Inversion of Control (IoC) 意味着一个对象不会新创建一个对象并依赖着它来完成工 ...
- 控制反转 (inversion of control)
The inversion of control (IoC) pattern is abstract; it says that one should move dependency creation ...
- IOC-控制反转(Inversion of Control),也成依赖倒置(Dependency Inversion Principle)
基本简介 IoC 亦称为 “依赖倒置原理”("Dependency Inversion Principle").差不多所有框架都使用了“倒置注入(Fowler 2004)技巧,这可 ...
- 设计模式之————依赖注入(Dependency Injection)与控制反转(Inversion of Controller)
参考链接: 依赖注入(DI) or 控制反转(IoC) laravel 学习笔记 —— 神奇的服务容器 PHP 依赖注入,从此不再考虑加载顺序 名词解释 IoC(Inversion of Contro ...
- Inversion of Control 控制反转 有什么好处
作者:Mingqi链接:https://www.zhihu.com/question/23277575/answer/169698662来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转 ...
- Spring 控制反转容器(Inversion of Control – IOC)
系列教程 Spring 框架介绍 Spring 框架模块 Spring开发环境搭建(Eclipse) 创建一个简单的Spring应用 Spring 控制反转容器(Inversion of Contro ...
- Spring学习3—控制反转(IOC)Spring依赖注入(DI)和控制反转(IOC)
一.思想理解 Spring 能有效地组织J2EE应用各层的对象.不管是控制层的Action对象,还是业务层的Service对象,还是持久层的DAO对象,都可在Spring的 管理下有机地协调.运行.S ...
- 控制反转和spring在项目中可以带来的好处
Spring实例化Bean的三种方式分别是: 1,xml配置使用bean的类构造器 <bean id="personService" class="cn.servi ...
- 控制反转(IoC)与依赖注入(DI)
1.控制反转(Inversion of Control)与依赖注入(Dependency Injection) 控制反转即IoC (Inversion of Control),它把传统上由程序代码直接 ...
- 控制反转(IoC)-解析与实现
控制反转(Inversion of Control)缩写:IoC是面向对象编程中框架级别里的一个重要的概念, 可以说Spring框架的核心就是基于IoC原理的. 这个概念到底是什么呢? 这么讲吧,一个 ...
随机推荐
- 关于rand()与srand()函数
rand函数功能为获取一个伪随机数(伪随机数的概念下面会有介绍). 一.函数名: rand(); 二.声明: int rand(); 三.所在头文件: stdlib.h 四.功能: 返回一个伪随机数. ...
- jquery源码学习之queue方法
队列模块的代码结构 静态方法jQuery下有queue,dequeue,_queueHooks这三种方法:静态方法不建议直接在外部调用: 实例方法.queue,.dequeue,.clearQueue ...
- archlinux更新错误
问题1 初始化下载: http://repo.archlinuxcn.org/x86_64/wps-office-10.1.0.5672_a21-2-x86_64.pkg.tar.xz 文件大小: 1 ...
- Hibernate的配置文件以及用法
一. 三大框架 Hibernate 1.安装hibernate插件至ecilpse 2.进行配置 2.1 主配置文件 <?xml version="1.0" encoding ...
- CSS BOX模型
对于box模型概念的理解以及它与决定元素最终尺寸的方式有何关系,是理解如何设定网 页上的元素位置的基础.box模型应用到块级元素.一个随之而来的概念,内联布局模型 定义了如何设定内联元素的位置. 对于 ...
- VC++ 在两个程序中 传递字符串等常量值的方法:使用了 WM_COPYDATA 消息的
消息作用: 在进程间共享数据(内部通过创建内存映射文件) 消息介绍:需要用到的数据结构/类型:typedef struct tagCOPYDATASTRUCT { ULONG_PTR dw ...
- 【POJ3237】Tree(树链剖分)
题意:在一棵N个节点,有边权的树上维护以下操作: 1:单边修改,将第X条边的边权修改成Y 2:区间取反,将点X与Y在树上路径中的所有边边权取反 3:区间询问最大值,询问X到Y树上路径中边权最大值 n& ...
- maven中添加servlet、jsp依赖
或者在eclipse中,右键项目名称->Maven->Add Dependency->输入servlet,会自动找到最新的版本(记得联网哦),如图:
- Html模板
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 5.0 Transitional//EN"> <!-- saved from ur ...
- ABAP BDC
REPORT程序中用BDC录入 DATA: GS_BDC TYPE BDCDATA, GT_BDC TYPE TABLE OF BDCDATA, GS_MSG TYPE BDCMSGCOLL, GT_ ...