我在项目中运用 IOC(依赖注入)--入门篇
之前就听同事说过依赖注入(dependency injection)、控制反转(Inversion of Control)。起初听的是一头雾水,试着在项目中运用了几次,总算明白了一些,抛砖引玉,与大家分享一下拙见。
其实依赖注入和控制反转指的都是同一个事情。什么是依赖注入了???
【个人理解】
以最熟悉的三层架构的项目来说,BLL层依赖DAL层,UI层依赖于BLL层,层层之间紧密联系。代码里到处都是new 对象。认识IOC后,发现IOC最大的好处就是解耦了对这种层级之间的依赖关系进。程序本身不在负责对象的创建和维护,而交给外部容器(IOC容器)来负责。外部容器在运行时动态地将依赖的对象注入到组件之中。
简单的来说就是在类型A中需要使用类型B的实例,而B实例的创建并不由A来负责,而是通过外部容器来创建。相比以往实例化对象的写法,确实很爽。
以往实例化都是这样的:
public class A
{
public A(B b)
{
this.B = b;
} public B B { get; set; } public void Test(B b)
{
Console.WriteLine(b.ToString());
}
}
A 类受B类的影响很大。A类的构造函数中,实例化B,且在A类的Test的方法中,需要判断B类是不是被实例化。A即创建B又需要维护B。用了IOC,解耦了这种依赖关系。接下来看看我在项目中是怎么简单应用的。
【项目简单试用】
一开始用的IOC容器是Unity,四个字,短小精干(用了有段日子。还有好多功能还需不断去探索) 。网上还有其它的IOC容器,没有去了解过(个人认为,能把一个工具用会,用熟,用精,才是王道。)
我把项目中的一段代码摘出来,项目需求大致上是项目有个数据统计,它下面有三种不同的统计类型,需要与数据库交互,然后展示到页面。
首先需要Unity的类库,利用VS2012的库程序包管理工具去下载Unity的类库。
项目的结构是这样,标准的是三层架构,BLL和DAL都有接口层IBLL,IDAL。
首先我们按照不用IOC的方式来实现这个小需求。
IDAL,IBLL 创建接口 IAnalyse 接口里有个方法
public interface IAnalyse
{
/// <summary>
/// 显示结果
/// </summary>
void ShowResult();
}
DAL 层引用IDAL,创建类 Analyse.cs
public class Analyse:IDAL.IAnalyse
{
public void ShowResult()
{
Console.WriteLine("分析底层数据库交互");
}
}
BLL层引用IDAL,DAL,IBLL 创建 类 Analyse.cs
/// <summary>
/// 显示结果
/// </summary>
public void ShowResult()
{
////以前思路 需要引用IBLL,IDAL,DAL
IDAL.IAnalyse dal = new DAL.Analyse();
dal.ShowResult();
}
UI层用控制台应用程序来代替。需引用IBLL,BLL
class Program
{
static void Main(string[] args)
{
OldMethod();
Console.ReadKey();
} /// <summary>
/// 在使用IOC前的写法。需要引入IBLL,BLL
/// </summary>
static void OldMethod()
{
IBLL.IAnalyse bll = new BLL.Analyse();
bll.ShowResult();
}
}
按照以前的方法,每个层我们都在不断的new 对象。写到这里发现这些都是很中规中矩的写法,以前老师教的也是这样,可能你会觉得没啥不好的。我就假如:BLL.Analyse 的构造函数需要参数,参数为Class B ,去掉无参的构造函数,你是不是所有new 对象的地方都要更改。小项目也许还没有问题,如果是上百万的大项目咋办。这就是所谓的层与层之间的耦合度高。(个人拙见,多多指教)
接下来我们用 IOC 来解耦。在Program.cs 增加 IOCMethod1 方法
static void Main(string[] args)
{
//OldMethod();
IOCMethod1();
Console.ReadKey();
} static void IOCMethod1()
{
IUnityContainer container=new UnityContainer();
////在容器中注册一种类型,它是一个类型的映射,接口类型是IAnalyse,希望返回的类型是Analyse
container.RegisterType<IBLL.IAnalyse, BLL.Analyse>();
////第二种写法
//container.RegisterType(typeof (IBLL.IAnalyse), typeof (BLL.Analyse));
IBLL.IAnalyse bll = container.Resolve<IBLL.IAnalyse>();
bll.ShowResult();
}
使用unity就三步:
第一,new IOC 容器
第二,调用RegisterType 注册类型。这里有多种注册形式。可以注册单例的、构造函数有参数的。
第三,调用Resolve 创建对象
(认识IOC 简单吧 O(∩_∩)O)
到这,你会发现,UI层 仍然引用了IBLL,BLL,RegisterType方法需要这两个类库。既然是解耦,就得解耦彻底些。有什么方法???
我在Core层 DependencyRegister.cs. 建立一个静态方法,在程序运行开始的时候,注册所有的类型。UI 层移除BLL ,引用Core
namespace Core
{
/// <summary>
/// 类型注册
/// </summary>
public class DependencyRegister
{ public static IUnityContainer DependencyRegisterContainer()
{
IUnityContainer container = new UnityContainer();
container.RegisterType<IBLL.IAnalyse, BLL.Analyse>()
.RegisterType<IDAL.IAnalyse, DAL.Analyse>();
return container;
}
}
} ////UI层 先移除BLL,引用Core
static void Main(string[] args)
{ IOCMethod2();
Console.ReadKey();
} static void IOCMethod2()
{ IUnityContainer container = DependencyRegister.DependencyRegisterContainer();
IBLL.IAnalyse bll = container.Resolve<IBLL.IAnalyse>();
bll.ShowResult();
}
这样达到了解耦的目标,如何需要更改类的构造函数,只需更改Core DependencyRegister.cs 就可以了。
【其它解耦方式】
建立core是用了自己得方法来实现解耦的,其实unity还有更觉得,通过配置文件 app.config 来实现。用的是 Microsoft.Practices.Unity.Configuration.dll
<!-- 程序集-->
<assembly name="IBLL"/>
<assembly name="IDAL"/>
<!--要返回的类型-->
<alias alias="BLLAnalyse1" type="BLL.Analyse, BLL" />
<container name="ContainerAnalyse">
<register type="IBLL.IAnalyse" name="BLLAnalyse1" mapTo="BLLAnalyse1" />
</container>
private static void IOCMethod3()
{
////通过配置文件注册所有类型
IUnityContainer container=new UnityContainer();
UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Configure(container, "ContainerAnalyse");
IBLL.IAnalyse bll = container.Resolve<IBLL.IAnalyse>("BLLAnalyse1");
bll.ShowResult();
}
【投机取巧】
无论是使用全局方法,或者 配置文件,都是注册类的形式不同。每种方法都需要调用Resolve 来创建对象。有没有连改方法都不用调用的形式。
不用多说,直接上代码:
namespace BLL
{
public class Analyse:IBLL.IAnalyse
{
////使用依赖注入
[Dependency]
public IDAL.IAnalyse dal { get; set; }
/// <summary>
/// 显示结果
/// </summary>
public void ShowResult()
{
////以前思路 需要引用IBLL,IDAL,DAL
//IDAL.IAnalyse dal = new DAL.Analyse(); dal.ShowResult();
}
}
}
使用[Dependency]属性。说实话,它的用法还有些没有弄明白。希望明白这个得多指教指教。
献丑了,有什么不对的地方希望大家多多指教。Unity 功能很多,这篇只不过是凤毛麟角,还有什么构造注入,属性注入、单例的应用。这些,将在下篇继续分享。希望大家继续关注,多多指教。
我在项目中运用 IOC(依赖注入)--入门篇的更多相关文章
- Android开源项目发现--- 工具类依赖注入DI篇(持续更新)
通过依赖注入减少View.服务.资源简化初始化,事件绑定等重复繁琐工作 1. AndroidAnnotations(Code Diet) android快速开发框架 项目地址:https://gith ...
- 我在项目中运用 IOC(依赖注入)--实战篇
上一篇<我在项目中运用 IOC(依赖注入)--入门篇>只是简单的使用 IOC.实际项目使用 IOC 的情景复杂多了,比如说,构造函数有多个参数,有多个类继承同一个接口... Unity都有 ...
- 深入浅出spring IOC中三种依赖注入方式
深入浅出spring IOC中三种依赖注入方式 spring的核心思想是IOC和AOP,IOC-控制反转,是一个重要的面向对象编程的法则来消减计算机程序的耦合问题,控制反转一般分为两种类型,依赖注入和 ...
- 转:深入浅出spring IOC中四种依赖注入方式
转:https://blog.csdn.net/u010800201/article/details/72674420 深入浅出spring IOC中四种依赖注入方式 PS:前三种是我转载的,第四种是 ...
- Spring 之 控制反转(IoC), 依赖注入(DI)和面向切面(AOP)
关于依赖注入, 这篇博文写的非常简单易懂. https://github.com/android-cn/blog/tree/master/java/dependency-injection 此外, 博 ...
- ASP.NET MVC IOC依赖注入之Autofac系列(二)- WebForm当中应用
上一章主要介绍了Autofac在MVC当中的具体应用,本章将继续简单的介绍下Autofac在普通的WebForm当中的使用. PS:目前本人还不知道WebForm页面的构造函数要如何注入,以下在Web ...
- ASP.NET MVC IOC依赖注入之Autofac系列(一)- MVC当中应用
话不多说,直入主题看我们的解决方案结构: 分别对上面的工程进行简单的说明: 1.TianYa.DotNetShare.Model:为demo的实体层 2.TianYa.DotNetShare.Repo ...
- 浅谈(IOC)依赖注入与控制反转(DI)
前言:参考了百度文献和https://www.cnblogs.com/liuqifeng/p/11077592.html以及http://www.cnblogs.com/leoo2sk/archive ...
- Spring学习-spring核心机制-IOC依赖注入
转载自:http://www.cnblogs.com/chenssy/archive/2012/11/11/2765266.html 今天复习一下spring两大特性之一:IOC依赖注入,看了一下大佬 ...
- 【17MKH】我在框架中对.Net依赖注入的扩展
说明 依赖注入(DI)是控制反转(IoC)的一种技术实现,它应该算是.Net中最核心,也是最基本的一个功能.但是官方只是实现了基本的功能和扩展方法,而我呢,在自己的框架 https://github. ...
随机推荐
- C# AutoMapper 了解一下
什么是AutoMapper? 简单来说就是将一个对象映射到另一个对象的代码. 摆脱了繁琐的赋值过程 (最常见也就是Model -——ViewModel) AutoMapper安装 我使用的是VS201 ...
- Tomcat 7.x/8.x 优化
一.优化Connector http://www.aikaiyuan.com/8466.html tomcat的运行模式有3种 1)bio 默认的模式,性能非常低下,没有经过任何优化处理和支持. 2) ...
- 世界线(bzoj2894)(广义后缀自动机)
由于春希对于第二世代操作的不熟练,所以刚使用完\(invasion process\)便掉落到了世界线之外,错综复杂的平行世界信息涌入到春希的意识中.春希明白了事件的真相. 在一个冬马与雪菜同时存在的 ...
- JVM之JIT
JIT技术是JVM中最重要的核心模块之一.我的课程里本来没有计划这一篇,但因为不断有朋友问起,Java到底是怎么运行的?既然Hotspot是C++写的,那Java是不是可以说运行在C++之上呢?为了澄 ...
- Flask从入门到精通之静态文件
Web 程序不是仅由Python 代码和模板组成.大多数程序还会使用静态文件,例如HTML代码中引用的图片.JavaScript 源码文件和CSS. 在前面的章节中,我们曾检查hello.py 程序的 ...
- 如何通过Python暴力破解网站登陆密码
首先申明,该文章只可以用于交流学习,不可以用于其他用途,否则后果自负. 现在国家对网络安全的管理,越来越严,但是还是有一些不法网站逍遥法外,受限于国内的人力.物力,无法对这些网站进行取缔. 今天演示的 ...
- vue的无缝滚动插件vue-seamless-scroll的安装与使用
npm安装地址 https://www.npmjs.com/package/vue-seamless-scroll 命令行执行: npm install vue-seamless-scroll --s ...
- error: failed to push some refs to 'https://github.com/username/python.git'
解决error: failed to push some refs to 'https://github.com/bluepen/python.git' 当我们在使用git工具上传我们自己的代码时,可 ...
- linux中进程和计划任务管理
进程和计划任务管理 1. 程序和进程的关系 程序:保存在硬盘.光盘等介质中的可执行代码和数据:静态保存的代码 进程:在 CPU 及内存中运行的程序代码:动态执行的代码:父.子进程:每个进程可以创建一个 ...
- Android_Universal-Image-Load使用
一,快速使用(确保ImageLoader只初始化一次,这样图片缓存会更加优秀.) 场景:为ImageView设置一张指定Uri的图片. 1,导包,配置联网,读写SD卡权限. 2,初始化: ImageL ...