IOC杂谈(一)初识IOC
初衷
发现学习东西不单只是看,用,还有很重要一点就是记录,不然过个几个月再用到相同的知识时,你会发现你已经丢得差不多了,故此开始在博客园记录的同时也与各位同行分享知识。
正题
关于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的更多相关文章
- 深入理解DIP、IoC、DI以及IoC容器
摘要 面向对象设计(OOD)有助于我们开发出高性能.易扩展以及易复用的程序.其中,OOD有一个重要的思想那就是依赖倒置原则(DIP),并由此引申出IoC.DI以及Ioc容器等概念.通过本文我们将一起学 ...
- 对依赖倒置原则(DIP)及Ioc、DI、Ioc容器的一些理解
1.概述 所谓依赖倒置原则(Dependence Inversion Principle)就是要依赖于抽象,不要依赖于具体.简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模 ...
- 深入理解DIP、IoC、DI以及IoC容器(转)
深入理解DIP.IoC.DI以及IoC容器 摘要 面向对象设计(OOD)有助于我们开发出高性能.易扩展以及易复用的程序.其中,OOD有一个重要的思想那就是依赖倒置原则(DIP),并由此引申出IoC.D ...
- IoC 之 2.2 IoC 容器基本原理(贰)
2.2.1 IoC容器的概念 IoC容器就是具有依赖注入功能的容器,IoC容器负责实例化.定位.配置应用程序中的对象及建立这些对象间的依赖.应用程序无需直接在代码中new相关的对象,应用程序由IoC ...
- IoC 之 2.1 IoC基础(壹)
2.1.1 IoC是什么 Ioc-Inversion of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器 ...
- 【转】深入理解DIP、IoC、DI以及IoC容器
原文链接:http://www.cnblogs.com/liuhaorain/p/3747470.html 前言 对于大部分小菜来说,当听到大牛们高谈DIP.IoC.DI以及IoC容器等名词时,有没有 ...
- 再看IOC, 读深入理解DIP、IoC、DI以及IoC容器
IoC则是一种 软件设计模式,它告诉你应该如何做,来解除相互依赖模块的耦合.控制反转(IoC),它为相互依赖的组件提供抽象,将依赖(低层模块)对象的获得交给第三方(系统)来控制,即依赖对象不在被依赖模 ...
- 对依赖倒置原则(DIP)及Ioc、DI、Ioc容器的一些理解(转)
所谓依赖倒置原则(Dependence Inversion Principle)就是要依赖于抽象,不要依赖于具体.简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合 ...
- 不可不知的DIP、IoC、DI以及IoC容器
面向对象设计(OOD)有助于我们开发出高性能.易扩展以及易复用的程序.当中.OOD有一个重要的思想那就是依赖倒置原则(DIP),并由此引申出IoC.DI以及Ioc容器等概念. 本文首先用实例阐述四个概 ...
- DIP、IoC、DI以及IoC容器
深入理解DIP.IoC.DI以及IoC容器 摘要 面向对象设计(OOD)有助于我们开发出高性能.易扩展以及易复用的程序.其中,OOD有一个重要的思想那就是依赖倒置原则(DIP),并由此引申出IoC.D ...
随机推荐
- 201521123026《Java程序设》 第10周学习总结
1. 本章学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 1.守护线程:setDaemon(true or false),如果所有前台线程死亡,守护线程自动结束,一般 ...
- 【干货】教你如何利用fullPage.js以及move.js插件打造高端大气的网站效果!
前言: 如今我们经常能见到全屏网站,尤其是国外网站.这些网站用几幅很大的图片或色块做背景,再添加一些简单的内容,显得格外的高端大气上档次. 在学习过jQuery插件之后,才发现之前的很多网站特效完全可 ...
- Hibernate第六篇【多对多映射、一对一映射】
前言 前面已经讲解了一对多和多对一的映射是怎么配置了,也讲解了inverse和cascade属性对关联关系的影响,本博文讲解多对多的映射和一对一的映射! 多对多映射 需求:一个项目由多个员工开发,一个 ...
- 从C#到TypeScript - 高级类型
C# vs TypeScript - 高级类型 上一篇讲了基础类型,基本上用基础类型足够开发了,不过如果要更高效的开发,还是要看下高级类型,这篇和C#共同点并不多,只是延用这个主题. 联合类型 可以从 ...
- Oracle的trim( )、ltrim( )、rtrim( )三个函数的用法及注意事项
学习一下用法整理trim().ltrim().rtrim()的用法 trim().ltrim().rtrim()三个函数有两个作用,分别是: 一.去除字符串前后空格(基本用法) trim(string ...
- 7-21(排序) PAT排名汇总
计算机程序设计能力考试(Programming Ability Test,简称PAT)旨在通过统一组织的在线考试及自动评测方法客观地评判考生的算法设计与程序设计实现能力,科学的评价计算机程序设计人才, ...
- 【小程序】微信小程序实现各种特效实例
写在前面 最近在负责一个微信小程序的前端以及前后端接口的对接的项目,整体上所有页面的布局我都已经搭建完成,里面有一些常用的特效,总结一下,希望对大家和我都能有所帮助 实例1:滚动tab选项卡 先看一下 ...
- 1289 大鱼吃小鱼 1305 Pairwise Sum and Divide 1344 走格子 1347 旋转字符串 1381 硬币游戏
1289 大鱼吃小鱼 有N条鱼每条鱼的位置及大小均不同,他们沿着X轴游动,有的向左,有的向右.游动的速度是一样的,两条鱼相遇大鱼会吃掉小鱼.从左到右给出每条鱼的大小和游动的方向(0表示向左,1表示向右 ...
- 【笔记】Kali linux的安装 和 一些使用前的准备工作(原创+转载)
该博文只记录笔者的蛇皮使用经历,纯新手= =,可能借鉴意义也可能没有(T _ T),侵删. 目录 kali linux 在个人计算机和在VirtualBox下的安装 kali linux 使用前准备工 ...
- C语言判断电脑的大、小端机
#include int main() { int x = 0x1234; if (char(x) == 0x34) { printf("小端机!\n"); } else ...