初衷

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

正题

关于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. 【干货】教你如何利用fullPage.js以及move.js插件打造高端大气的网站效果!

    前言: 如今我们经常能见到全屏网站,尤其是国外网站.这些网站用几幅很大的图片或色块做背景,再添加一些简单的内容,显得格外的高端大气上档次. 在学习过jQuery插件之后,才发现之前的很多网站特效完全可 ...

  2. 生成/etc/shadow文件中的密码

    shadow文件的格式就不说了.就说说它的第二列--密码列. 通常,passwd直接为用户指定密码就ok了.但在某些情况下,要为待创建的用户事先指定密码,还要求是加密后的密码,例如kickstart文 ...

  3. SpringMVC 构建Restful风格 及问题处理

    基本的请求URL: /person/{id}  GET  得到id的person /person POST      新增person /person/{id}  PUT  更新id的person / ...

  4. python数据分析panda库

    panda内有两种数据结构,Series()和DataFrame() >>> a=pd.Series([1,2],index=['a','b']) >>> a a ...

  5. JVM 运行时数据区总结 栈 堆 堆大小配置总结

    1. 程序计数器 线程私有 当前线程所执行的字节码的行号指示器 2. 虚拟机栈 线程私有 存:Java方法(局部变量表(基本数据类型).操作数栈.动态链栈.方法出口) StackOverflowErr ...

  6. 关于XCode9的一些问题

    最近几天一直在做一项工作,为新项目在做搭建框架的前期准备,然后恰逢更新iOS11和XCode9,笔者心急的尝了个先,发现了一些问题,记录一下,如果有相同问题的程序猿,也可以参考一下. 目前问题遇到两点 ...

  7. BZOJ2431_逆序对数列_KEY

    转自YXDs 题目传送门 不知道今天是怎么了,可能是空调吹多了吧,一直不在状态,连递推题我都做不来了--(扎Zn了老Fe--) 然而,不管环境如何恶劣,我们仍要努力学习,为了自己的明天而奋斗.(说的好 ...

  8. vue+axios 前端实现登录拦截(路由拦截、http拦截)

    一.路由拦截 登录拦截逻辑 第一步:路由拦截 首先在定义路由的时候就需要多添加一个自定义字段requireAuth,用于判断该路由的访问是否需要登录.如果用户已经登录,则顺利进入路由, 否则就进入登录 ...

  9. Highway Networks

    一 .Highway Networks 与 Deep Networks 的关系 深层神经网络相比于浅层神经网络具有更好的效果,在很多方面都已经取得了很好的效果,特别是在图像处理方面已经取得了很大的突破 ...

  10. Linux学习——shell编程之运算符

    shell编程之运算符 一:shell中常见算术运算符号和优先级 二:算术运算符 Shell 变量:是弱类型!不能进行加减乘除!比较麻烦! 例子 :shell变量弱类型 a=11 b=22 echo ...