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 ...
随机推荐
- Bootstrap栅格系统用法--Bootstrap基础
1.栅格系统实现布局的原理 1)Bootstrap把屏幕的宽度拆分成12格(列),每一格像素的多少由设备屏幕分辨率决定,我们在开发项目的过程中不需要去指定像素或者百分比. 2)不同范围的分辨率对应不同 ...
- Spring第五篇【cglib、手动实现AOP编程】
前言 到目前为止,已经简单学习了Spring的Core模块.也会怎么与Struts2框架进行整合了-.于是我们就开启了Spring的AOP模块了-在讲解AOP模块之前,首先我们来讲解一下cglib代理 ...
- Oracle-表的字段增加修改删除操作
表结构修改 ALTER TABLE SCOTT.TEST RENAME TO TEST1--修改表名 ALTER TABLE SCOTT.TEST RENAME COLUMN NAME TO NAME ...
- hibernate中Query的list和iterator区别(续)
打开cache后query的list和iterator方法区别 将query 的cache打开的话,缓存的是query本身,以hql 生成的 sql ,再加上参数,分页等信息做为key值,而不是que ...
- Sublime Text 3 全程详细图文原创教程
Sublime Text 3 全程详细图文原创教程(持续更新中...) 一. 前言 使用Sublime Text 也有几个年头了,版本也从2升级到3了,但犹如寒天饮冰水,冷暖尽自知.最初也是不知道从何 ...
- HTML5基本标签的使用
第一次写这种东西,肯定存在许多不足之处,还望大家多多担待,我会继续加油的!我也是一名HTML5的初学者,只是将这几周在课堂上所听到的东西分享给大家. 下面给大家介绍一下H5! 一.<!DOCTY ...
- Jquery Ajax type的4种类型
Ajax type这个里面填什么呢?通常大家都会说get和post.那么还有2个是什么呢 $.ajax({ url: 'http://www.cnblogs.com/youku/', type: '' ...
- 动易CMS-搜索结果页显示自定义字段
最终的页面: 步骤: 1.搜索标签代码 <input id="keyword" type="text" class="text" on ...
- Java源码学习:HashMap实现原理
AbstractMap HashMap继承制AbstractMap,很多通用的方法,比如size().isEmpty(),都已经在这里实现了.来看一个比较简单的方法,get方法: public V g ...
- Qt学习之路MainWindow学习过程中的知识点
一.Qt的GUI程序有一个常用的顶层窗口,叫做MainWindow MainWindow继承自QMainWindow.QMainWindow窗口分成几个主要的区域: 二.QAction类 QAct ...