控制反转(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原理的. 这个概念到底是什么呢? 这么讲吧,一个 ...
随机推荐
- JAVA的Random类[转]
在实际的项目开发过程中,经常需要产生一些随机数值,例如网站登录中的校验数字等,或者需要以一定的几率实现某种效果,例如游戏程序中的物品掉落等. 在Java API中,在java.util包中专门提供了一 ...
- VS2012调试时无法启动程序和拒绝访问问题汇总
很多人在使用VS2012的时候会出现下面所示的问题,我也是,而且不止一次,也不是同样的问题,我这里就把一些常见的解决方法罗列一下.
- Linux网络常用指令
5.1 网络参数设定使用的指令 ifconfig 查询 设定网络卡与 IP 网域等相关参数: ifup, ifdown 这两个档案是 script,透过更简单的方式来启动网络接口: route 查 ...
- SQL SELECT语句
基本SQL SELECT语句 1. 下面的语句是否可以执行成功 select ename , job , sal as salary from emp; 2. 下面的语句 ...
- apache+tomcat分布式搭建
windows 下Apache和tomcat整合 负载均衡session共享 准备工作: 1. Apache 2.2.4 下载地址:http://cztele1.skycn.com/down/apac ...
- java 封装httpclient 的get 和post 请求
import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; import java.util. ...
- jquery中append跟prepend的用法
jquery中append和prepend的用法 append 是插入到元素中,并放到元素内的最后面prepend 是插入到元素中,并放到元素内的最前面例$("body"). ...
- model is null
在action实现页面跳转过程中,可以实现页面的跳转,但页面无内容,无渲染,在控制台输出视图名,会报出url路径+"model is null" 这是在导包的错,正确的为: imp ...
- 技术英文单词贴--V
V validate 验证,确认,使生效 verify 核实,查实,验证 version 版本,译文 via 通过,凭借,经过 prep
- jQuery Mobile 过渡效果
jQuery Mobile 包含了允许您选择页面打开方式的 CSS 效果. jQuery Mobile 过渡效果 jQuery Mobile 拥有一系列关于如何从一页过渡到下一页的效果. 注释:如需实 ...