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 ...
随机推荐
- sublime text3 好用的插件!!!
1.首先,你要保证sublime有Package Control,所以,如果没有,那么将Ctrl+`打开sublime控制台,将下列代码复制进去! import urllib.request,os; ...
- 跨站数据请求哪家强——青出于蓝的jsonp
/* * 跨站数据请求哪家强--青出于蓝的jsonp数据格式 * @author gj * @date 2017-09-15 */ 先哲有云"青,取之于蓝,而青于蓝:冰,水为之,而寒于水&q ...
- Window10中利用Windbg与虚拟机(window7)中调试驱动建立方法
想起自己的windbg配置就转载:eqera的windows内核调试配置,真的是获益良多希望他不会介意我转载他的博客,帮了我很多,记录下来给我也给大家, 其中我主要看的是VMWare的pipe建立,而 ...
- 纳税服务系统【用户模块之使用POI导入excel、导出excel】
前言 再次回到我们的用户模块上,我们发现还有两个功能没有完成: 对于将网页中的数据导入或导出到excel文件中,我们是完全没有学习过的.但是呢,在Java中操作excel是相对常用的,因此也有组件供我 ...
- Dijkstra堆优化学习
最短路径例题 今天特地学习了Dijkstra的堆优化(主要是慕名已久). 我们需要一个堆来记录[编号,到编号这个点的最短路径值(当然只是当前的)] 与原来的Dijkstra操作基本一致,主要有以下几点 ...
- Linux入门之常用命令(11)复制cp及scp
[scp] ================== scp 命令 ================== scp 可以在 2个 linux 主机间复制文件: 命令基本格式: scp [可选参 ...
- Spring -- 配置bean的三种方法
配置通过静态工厂方法创建的bean public class StaticBookFactory { //静态工厂方法: public static Book getBook(String bookN ...
- HDU3336 Count the string
居然一A了,说明对朴素的KMP还是有一定理解. 主要就是要知道next数组的作用,然后就可以计算每个i结尾的满足题意的串个数. #include<cstdio> #include<c ...
- ZOJ2402 Lenny's Lucky Lotto List 简单DP
Lenny's Lucky Lotto Lists Time Limit: 2 Seconds Memory Limit:65536 KB Lenny likes to play the g ...
- 新版MySql 5.6.20,安装后无法登陆的解决办法
1.按照提示安装好mysql 2.运行cmd 进入mysql的安装目录,我的安装目录C:\Program Files\MySQL\MySQL Server 5.6\bin 输入 cd C:\Progr ...