关于控制反转(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)之我的理解的更多相关文章

  1. 控制反转Inversion of Control (IoC) 与 依赖注入Dependency Injection (DI)

    控制反转和依赖注入 控制反转和依赖注入是两个密不可分的方法用来分离你应用程序中的依赖性.控制反转Inversion of Control (IoC) 意味着一个对象不会新创建一个对象并依赖着它来完成工 ...

  2. 控制反转 (inversion of control)

    The inversion of control (IoC) pattern is abstract; it says that one should move dependency creation ...

  3. IOC-控制反转(Inversion of Control),也成依赖倒置(Dependency Inversion Principle)

    基本简介 IoC 亦称为 “依赖倒置原理”("Dependency Inversion Principle").差不多所有框架都使用了“倒置注入(Fowler 2004)技巧,这可 ...

  4. 设计模式之————依赖注入(Dependency Injection)与控制反转(Inversion of Controller)

    参考链接: 依赖注入(DI) or 控制反转(IoC) laravel 学习笔记 —— 神奇的服务容器 PHP 依赖注入,从此不再考虑加载顺序 名词解释 IoC(Inversion of Contro ...

  5. Inversion of Control 控制反转 有什么好处

    作者:Mingqi链接:https://www.zhihu.com/question/23277575/answer/169698662来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转 ...

  6. Spring 控制反转容器(Inversion of Control – IOC)

    系列教程 Spring 框架介绍 Spring 框架模块 Spring开发环境搭建(Eclipse) 创建一个简单的Spring应用 Spring 控制反转容器(Inversion of Contro ...

  7. Spring学习3—控制反转(IOC)Spring依赖注入(DI)和控制反转(IOC)

    一.思想理解 Spring 能有效地组织J2EE应用各层的对象.不管是控制层的Action对象,还是业务层的Service对象,还是持久层的DAO对象,都可在Spring的 管理下有机地协调.运行.S ...

  8. 控制反转和spring在项目中可以带来的好处

    Spring实例化Bean的三种方式分别是: 1,xml配置使用bean的类构造器 <bean id="personService" class="cn.servi ...

  9. 控制反转(IoC)与依赖注入(DI)

    1.控制反转(Inversion of Control)与依赖注入(Dependency Injection) 控制反转即IoC (Inversion of Control),它把传统上由程序代码直接 ...

  10. 控制反转(IoC)-解析与实现

    控制反转(Inversion of Control)缩写:IoC是面向对象编程中框架级别里的一个重要的概念, 可以说Spring框架的核心就是基于IoC原理的. 这个概念到底是什么呢? 这么讲吧,一个 ...

随机推荐

  1. 异步编程:When.js快速上手

    前些天我在团内做了一个关于AngularJS的分享.由于AngularJS大量使用Promise,所以我把基于Promise的异步编程也一并介绍了下.很多东西都是一带而过,这里再记录下. Angula ...

  2. Java基础以及与C++的一些对比

    这两天回忆一些Java基础,感觉自己很多地方都不是很牢固,也花费在不少时间和不少流量在手机上查资料. 还是写下来这些东西以免再忘记. 同时还是要记住多动手,编程最重要的就是动手敲啊,有想法有疑问就要自 ...

  3. SVD++:推荐系统的基于矩阵分解的协同过滤算法的提高

    1.背景知识 在讲SVD++之前,我还是想先回到基于物品相似的协同过滤算法.这个算法基本思想是找出一个用户有过正反馈的物品的相似的物品来给其作为推荐.其公式为:

  4. XidianOJ 1176 ship

    题目描述 The members of XDU-ACM group went camp this summer holiday. They came across a river one day. T ...

  5. XidianOJ 1183 Water Problem: Items divided

    题目描述 Youyouyouyou is very interested in math, one day, an idea came into his mind that how many ways ...

  6. 温习SQL server

    做了好几年的管理工作,技术上有些退步,现在又一一捡起来啦, 以下最近几天看到的好文章, SQL Server约束 http://blog.csdn.net/qq61394323/article/det ...

  7. UVa 10071 - Back to High School Physics

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=94&page=s ...

  8. javascript中document.appendChild和document.body.appendChild的问题

    在IE7中 var conentDiv = document.createElement("div"); document .body .appendChild(conentDiv ...

  9. windows10-桌面图标不见了,资源管理器的桌面中可以看到??

    问题描述: 1. 桌面的图标,在桌面上看不到, 但是在通过资源管理器可以看到, 图标仍然在桌面 2. 桌面仍然可以右击, 就是看不见新建或者拷贝到桌面的所有图标 解决方案: Google 后请参考: ...

  10. 转 A Week with Mozilla's Rust

    转自http://relistan.com/a-week-with-mozilla-rust/ A Week with Mozilla's Rust I want another systems la ...