初衷

发现学习东西不单只是看,用,还有很重要一点就是记录,不然过个几个月再用到相同的知识时,你会发现你已经丢得差不多了,故此开始在博客园记录的同时也与各位同行分享知识。

正题

关于IOC,在刚工作时就接触到了这个技术,原谅我当时年轻不求甚解,以为IOC就仅仅只是控制反转,只要不直接创建我所需要的类就OK。

当时公司的框架正在使用Spring.Net,使用了Spring的IOC解耦的标准三层架构。

效仿其结构,当时我自己用反射做了一个简单的IOC容器,当时甚至还不知道什么叫IOC容器,只是感觉自己做了一个有点特别的工厂。

还自以为已经掌握了IOC而沾沾自喜,后来慢慢接触很多优秀的开源框架(ABP,Enode等),看了一些DDD(领域驱动设计)的书,才发现当初自己了解的IOC不过冰山一角。

所以一直很想写写关于这方面的一些总结与经验。

本篇作为开篇,还是想先对不了解IOC的朋友做个简单的介绍。

话不多说,我们来看看例子。

首先看看不使用IOC情况下的例子:

        public void GetServiceData()
{
var service = new DataService();
var dataList = service.GetDataSource();
Console.WriteLine("Get Data:" + dataList.ToString());
}

这个简单的例子里,我们所获取的数据由DataService类提供,我们直接创建了一个新的实例来使用它,这样一来就与该类产生了强依赖,如果DataService发生了变化,比如名字变更,或者业务需要我们使用另一种数据服务NewDataService时,

我们都不得不去更改代码,这违反了OCP(开闭原则)。

如果读过设计模式的看官可能会想到工厂模式,好的,我们来尝试一下。

    public class ServiceFactory
{
public static DataService GetDataService()
{
var component = new DataService();
return component;
}
}

我们把实体的创建放到了一个静态工厂里面,然后源代码变成这样了。

        public void GetServiceData()
{
var dataList = ServiceFactory.GetDataService().GetDataSource();
Console.WriteLine("Get Data:" + dataList.ToString());
}

看上去似乎不错,对Service层的依赖已经不存在了。

但又增加了新的依赖——ServiceFactory,代码仍然不够优雅。

不过值得一提的是,工厂通常来说变化是很小的,这种形式的解耦还是可以接受的。

刚才提到的问题还有一个很重要的点没有解决——当业务需要我们用一个具有相同行为的服务去替换,或者拓展时。

业务场景来说的话,就比如到医院就诊这个服务,大致的行为流程可以分为:挂号,等待,就诊,结账这四个行为。

我们在完成人民医院的就诊服务调用后,可能以后会需要调用门诊部或者其他医院的就诊服务,而这几个服务的行为是一致或相近的,无非实现方法不一样,比如挂号,可能是在前台挂也可能是通过机器挂,但都是挂号。

这个时候我们如果去修改调用就诊服务的代码块就不是一个理想的做法,所以我们要遵从DIP(依赖倒置原则)来进行编程,简单来说,就是针对抽象而不是具体类,抽象包括抽象类和接口。

我们用接口来改造上面的代码。

    public interface IDataService
{
int GetDataSource();
} public class DataService : IDataService
{
public int GetDataSource()
{
return ;
}
} public class NewDataService : IDataService
{
public int GetDataSource()
{
return ;
}
}

调用代码:

    public class ServiceFactory
{
public static IDataService GetDataService()
{
var component = new DataService();
return component;
}
} public void GetServiceData()
{
var dataList = ServiceFactory.GetDataService().GetDataSource();
Console.WriteLine("Get Data:" + dataList.ToString());
}

好的,现在我们需要更换成另外一个数据服务时,只要修改工厂里的方法就行了……

好吧,这样看来我们只是把问题的发生场所换到工厂里了而已,

不过不要沮丧,我们已经进了一步。想象一下,如果你的项目里有数十个用到DataService的地方,我想你在修改的时候会有遗漏的风险。

然而如果放在工厂里去修改,我们只需要修改工厂的代码就行了,虽然依旧违反了OCP,但它确实起到了集中管理的良好效果。

是时候探讨一下工厂模式以外的解耦方法了,考察调用的方法里,我们只得到了一个接IDataService。

既然如此,那一开始就把这个接口放在类里面不就好了?

听上去似乎不错,不过它的具体实现又该从哪里得到呢?

思考一下一个类最常与外部做数据交互的东西有两个,

一,属性

二,方法参数

好的,得到这两点信息后,我们考虑如何实现。

为了保证类在调用服务时,我们的具体实现已经被传入了类当中,我们必须在类实例化的时候就给他传入具体实现,这个过程就是我们耳熟能详的DI(依赖注入)

如果我们通过属性去注入,那就是属性注入。

而选择方法,就被称为方法注入,由于我们必须在实例化时注入依赖,最佳选择肯定是在构造器中传入依赖,这种情况就被称为构造器注入。

让我们来看一下两种注入方法的实现。

属性注入:

        public IDataService IDataService { get; set; }

        public void GetServiceData()
{
var dataList = IDataService.GetDataSource();
Console.WriteLine("Get Data:" + dataList.ToString());
}

构造器注入

    public class CallClass
{ private IDataService _dataService; public CallClass(IDataService injectService)
{
_dataService = injectService;
} public void GetServiceData()
{
var dataList = _dataService.GetDataSource();
Console.WriteLine("Get Data:" + dataList.ToString());
}
}

这样我们的调用类就完全从依赖中解放出来,只要暴露出它所需要的行为,具体实现由外部创建它的类来实现。

通用规则是使用构造器注入来注入一些我们必须的依赖,比如应用服务层的业务服务

使用属性注入来注入一些可选的参数,比如日志服务。

在Autofac的官方手册的最佳实践中提到了尽量使用构造器注入。

由此可见构造器注入的常用性。

到此为止对IOC和DI的介绍就此结束。

可能有的看官会问,那外部创建它的类不是也要考虑具体注入哪个类不是吗?

这就涉及具体项目的使用问题了,我们使用IOC框架就在于更灵活而可控地去注入我们所需要的依赖。

所以下来的随笔我逐一介绍当前最流行的几个IOC框架,并比较它们的易用性和一些不同点。

不过如果把关注点都放在我们的调用类上面,利用属性注入和构造器注入我们已经实现了一个符合迪米特法则而低耦合的调用类,

这对于这个调用类来说已经足够了。

文笔中若有疏忽之处,欢迎斧正。

IOC杂谈(一)初识IOC的更多相关文章

  1. 深入理解DIP、IoC、DI以及IoC容器

    摘要 面向对象设计(OOD)有助于我们开发出高性能.易扩展以及易复用的程序.其中,OOD有一个重要的思想那就是依赖倒置原则(DIP),并由此引申出IoC.DI以及Ioc容器等概念.通过本文我们将一起学 ...

  2. 对依赖倒置原则(DIP)及Ioc、DI、Ioc容器的一些理解

    1.概述 所谓依赖倒置原则(Dependence Inversion Principle)就是要依赖于抽象,不要依赖于具体.简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模 ...

  3. 深入理解DIP、IoC、DI以及IoC容器(转)

    深入理解DIP.IoC.DI以及IoC容器 摘要 面向对象设计(OOD)有助于我们开发出高性能.易扩展以及易复用的程序.其中,OOD有一个重要的思想那就是依赖倒置原则(DIP),并由此引申出IoC.D ...

  4. IoC 之 2.2 IoC 容器基本原理(贰)

    2.2.1  IoC容器的概念 IoC容器就是具有依赖注入功能的容器,IoC容器负责实例化.定位.配置应用程序中的对象及建立这些对象间的依赖.应用程序无需直接在代码中new相关的对象,应用程序由IoC ...

  5. IoC 之 2.1 IoC基础(壹)

    2.1.1  IoC是什么 Ioc-Inversion of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器 ...

  6. 【转】深入理解DIP、IoC、DI以及IoC容器

    原文链接:http://www.cnblogs.com/liuhaorain/p/3747470.html 前言 对于大部分小菜来说,当听到大牛们高谈DIP.IoC.DI以及IoC容器等名词时,有没有 ...

  7. 再看IOC, 读深入理解DIP、IoC、DI以及IoC容器

    IoC则是一种 软件设计模式,它告诉你应该如何做,来解除相互依赖模块的耦合.控制反转(IoC),它为相互依赖的组件提供抽象,将依赖(低层模块)对象的获得交给第三方(系统)来控制,即依赖对象不在被依赖模 ...

  8. 对依赖倒置原则(DIP)及Ioc、DI、Ioc容器的一些理解(转)

    所谓依赖倒置原则(Dependence Inversion Principle)就是要依赖于抽象,不要依赖于具体.简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合 ...

  9. 不可不知的DIP、IoC、DI以及IoC容器

    面向对象设计(OOD)有助于我们开发出高性能.易扩展以及易复用的程序.当中.OOD有一个重要的思想那就是依赖倒置原则(DIP),并由此引申出IoC.DI以及Ioc容器等概念. 本文首先用实例阐述四个概 ...

  10. DIP、IoC、DI以及IoC容器

    深入理解DIP.IoC.DI以及IoC容器 摘要 面向对象设计(OOD)有助于我们开发出高性能.易扩展以及易复用的程序.其中,OOD有一个重要的思想那就是依赖倒置原则(DIP),并由此引申出IoC.D ...

随机推荐

  1. CustomDialog——一个多功能、通用、可自定义的Dialog

    CustomDialog--一个多功能.通用.可自定义的Dialog  依赖 compile 'com.github.SiberiaDante:CustomDialog:v1.0.1'  说明[Cus ...

  2. pl/sql developer 连接服务器上的数据库

    1, 在本地安装的Oracle中找到目录 oracle\product\11.2.0\dbhome_1\network\admin, 它下面一般有两个文件可以进行编辑tnsnames.ora   li ...

  3. Qt Creator编译运行成功,但是显示系统找不到指定的文件(比如urlmon.dll动态链接库)

    问题: 以前自己写的一个QT界面程序,在win 7 的32位系统上运行没有出现任何问题,但是重装系统之后,同样的程序放到win10 的64位系统下运行会出现警告:onecoreuap\inetcore ...

  4. SpringMVC HelloWorld实例开发及部署

    SpringMVC HelloWorld实例开发及部署 2017-01-24 目录 1 Tomcat及Eclipse Tomcat插件安装配置  1.1 Tomcat的安装  1.2 Eclipse ...

  5. Tensorflow之卷积神经网络(CNN)

    前馈神经网络的弊端 前一篇文章介绍过MNIST,是采用的前馈神经网络的结构,这种结构有一个很大的弊端,就是提供的样本必须面面俱到,否则就容易出现预测失败.如下图: 同样是在一个图片中找圆形,如果左边为 ...

  6. 12 Nonlinear Transformation

    一.二次假设 实际上线性假设的复杂度是受到限制的, 需要高次假设打破这个限制 假设数据不是线性可分的,但是可以被一个圆心在原点的圆分开, 需要我们重新设计基于该圆的PLA等算法吗 不用, 只需要通过非 ...

  7. hibernate学习手记(2)

    1.javax.persistence.TransactionRequiredException: no transaction is in progress 出现该问题是我没有开启事务,我是在保存之 ...

  8. POJ-1273-Drainage Ditches(网络流之最大流)

    Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover patch. This ...

  9. End up with More Teams UVA - 11088

    End up with More Teams Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu ...

  10. NOIP2017SummerTraining0706

    个人感受:这套题也依旧在划水,和wqh在一起,然后也没怎么好好想,第一题开始时打了个思维很好的方法,但是事完全错误的:然后就开始第二题,然后第二题枚举20分,然后看答案多了25分,就拿了 45分:第三 ...