一、一个没有使用IoC的例子
IoC的全称是Inversion of Control,中文叫控制反转。要理解控制反转,可以看看非控制反转的一个例子。
public class MPGMovieLister { public Movie[] GetMPG() { var finder = new ListMovieFinder(); var allMovies = finder.FindAll(); return allMovies.Where(m => m.Name.EndsWith(".MPG")).ToArray(); } } public class ListMovieFinder { public List<Movie> FindAll() { return new List<Movie> { new Movie { Name = "Die Hard.wmv" }, new Movie { Name = "My Name is John.MPG" } }; } }
上面的例子中,类MPGMovieLister的作用是列出所有的mpg类型的电影,其中调用了类ListMovieFinder类的方法FindAll()来获取所有的电影。
这段代码看起来还不错,已经符合当前的需求了。
二、当需求发生变动时,非IoC遭遇到的困境
假如,这个时候,movie的列表获取不是直接创建一个list获取,而要求从某个文本文件读取,或者是数据库获取,又或者从web service中获取,我们怎么办?
第一步,再实现一个类, 比如FileMovieFinder,来实现从文本文件中读取Movie列表,再把MPGMovieLister中的这行代码,
var finder = new ListMovieFinder();
替换成
var finder = new FileMovieFinder();
那么这行代码就又能够符合要求了。
新的MPGMovieLister代码是这个样子:
public class MPGMovieLister { public Movie[] GetMPG() { var finder = new FileMovieFinder(); var allMovies = finder.FindAll(); return allMovies.Where(m => m.Name.EndsWith(".MPG")).ToArray(); } }
如果底层--获取数据的方式不确定,或者经常更改,MPGMovieLister的代码岂不是要频繁改动?
三、使用IoC彻底解决问题:
MPGMovieLister的功能都是依赖着具体的类,ListMovieFinder,FileMovieFinder。当需求发生变化的时候,就会导致MPGMovieLister的代码也要做相应的改动。
也就是说,MPGMovieLister直接依赖于ListMovieFinder和FileMovieFinder了。
跳出来看,MPGMovieLister的功能只是负责从列表中找出MPG的movie, 至于movie从什么地方来的,不是MPGMovieLister的职责,它也不需要关心。
而解耦合的方法就是”依赖于抽象,而不是依赖于具体”.
(这个例子非常类似于我们的做开发时候的持久层(数据层)和业务逻辑层,其实业务逻辑层也不关心数据是如何提供的,所以业务逻辑层也应当与持久层解耦合。)
实际解决之后的代码:
public class MPGMovieLister { public Movie[] GetMPG() { var finder = MovieFinderFactory.GetFinder(); var allMovies = finder.FindAll(); return allMovies.Where(m => m.Name.EndsWith(".MPG")).ToArray(); } } public class MovieFinderFactory { public static IMovieFinder GetFinder() { return new FileMovieFinder(); } } public interface IMovieFinder { List<Movie> FindAll() }
这里MPGMovieLister就依赖于IMovieFinder接口(依赖抽象), 实际运行时候的实例化由MovieFinderFactory来提供。这样,不同的Movie数据源只需要一个实现IMovieFinder 的类就可以了,不会对MPGMovieLister产生任何影响。
到这里,实际上已经完成了IoC, 控制权最初取决于MPGMovieLister中是如何实例化MovieFinder 的,现在它已经交出控制权,交由外部来提供具体实例对象了。
这里的MovieFinderFactory就已经是一个简陋的IoC容器功能了。
四、总结
IoC这种解决依赖的方法是面向对象方法的使用。现实世界中,这种方法无处不在。
比如,汽车不会强依赖于某个品牌的轮胎,任何公司生产的轮胎,只要符合汽车的接口,就可以装在这个汽车上使用。
还有电脑的USB接口,只要符合USB标准的外设,就都能够接上电脑使用。
解除依赖不仅让代码结构看起来更加合理,其带来的另一个好处是,各个部分可以单独的做单元测试,使得单元测试能够更加容易的进行。这个对于一些复杂度高的项目,对于保证项目的稳定性和可用性非常有意义。
真正的IoC容器比上面的MovieFinderFactory自然要好用和适用的多。下一篇文章将会介绍一个非常棒的IoC框架Autofac.
IoC容器Autofac(2)
一、使用自定义工厂类实现IoC的例子
我们回顾一下之前的代码:
//这个类的作用是筛选出MPG类型的电影 public class MPGMovieLister:IMovieFinder { public Movie[] GetMPG() { var finder = MovieFinderFactory.GetFinder();//这里调用工厂类获取具体的实例,得到一个电影列表 var allMovies = finder.FindAll(); return allMovies.Where(m => m.Name.EndsWith(".MPG")).ToArray(); } } public class MovieFinderFactory { public static IMovieFinder GetFinder() { return new ListMovieFinder(); } } public class ListMovieFinder :IMovieFinder { public List<Movie> FindAll() { return new List<Movie> { new Movie { Name = "Die Hard.wmv" }, new Movie { Name = "My Name is John.MPG" } }; } } public interface IMovieFinder { List<Movie> FindAll() }
这里MPGMovieLister已经不和具体的MovieFinder耦合了,而是依赖于MovieFinderFactory工厂类提供的IMovieFinder接口的具体实现来取Movie数据。
所以工厂类只要返回不同的实现IMovieFinder的实例,就能够让MovieLister从列表,文本,数据库,web service …… 中获取数据。
二、改造代码,去除MovieFinderFactory
在应用Autofac替换MovieFinderFactory之前,我们先从代码中去掉MovieFinderFactory, 改动之后的代码是这样:
public class MPGMovieLister { private readonly IMovieFinder _movieFinder; //增加了构造函数,参数是IMovieFinder对象 public MPGMovieLister(IMovieFinder movieFinder) { _movieFinder = movieFinder; } public Movie[] GetMPG() { var allMovies = _movieFinder.FindAll(); return allMovies.Where(m => m.Name.EndsWith(".MPG")).ToArray(); } } public interface IMovieFinder { List<Movie> FindAll() }
我们去掉了工厂类MovieFinderFactory, 改造了MPGMovieLister, 添加了一个构造函数, 构造函数要求使用MPGMovieLister时,需要提供一个IMovieFinder的实例。
三、应用Autofac替代工厂类
应用Autofac改造上面的代码。
第一步: 从Nuget中添加Autofac引用
第二步:
* 创建一个ContainerBuilder对象(ContainerBuilder从字面的意思就是用来创建Container(容器)的,而Conainter就是我们从中取各种我们需要对象的地方)
* 注册我们后面将从容器中取出对象的类型。
代码是这样:
var builder = new ContainerBuilder();// builder.RegisterType<ListMovieFinder>().AsImplementedInterfaces();//注册ListMovieFinder类型,这里的AsImplementedInterfaces表示以接口的形式注册 builder.RegisterType<MPGMovieLister>();//注册MPGMovieLister类型
* 创建容器
_container = builder.Build();
第三步: 在程序中使用 _container容器:
var lister = _container.Resolve<MPGMovieLister>(); foreach (var movie in lister.GetMPG()) { Console.WriteLine(movie.Name); }
理解一下Autofac为我们在背后做了什么:
首先,我们注册了类型ListMovieFinder和MPGMovieLister,这样容器就能够知道如何创建这两种类型的实例了。(类其实是创建对象的模板,当我们把模板注册给Autofac, 它就会遵循这个模板为我们提供实例)
后面的代码中,我们调用Resolve方法,取出一个MPGMovieLister的实例。
_container.Resolve<MPGMovieLister>();
这里还有一个需要解释的,对于MPGMovieLister类型,我们为Autofac提供了类型, 但是当Autofac创建MPGMovieLister的实例, 调用它的构造函数的时候,却遇到了问题:
它的构造函数需要提供一个IMovieFinder的实例作为参数的, 聪明的Autofac要在自己的容器里找找,看看没有有办法提供一个IMovieFinder的实例。
这个时候Autofac会发现我们注册过ListMovieFinder, 并且通过AsImplementedInterfaces()方法,指明了就是为接口IMovieFinder提供实例的。
所以Autofac会创建一个ListMovieFinder的实例,作为创建MPGMovieLister时,提供给构造函数的参数。
builder.RegisterType<ListMovieFinder>().AsImplementedInterfaces();
四、当需求发生变动, Autofac如何应对?
上面的例子中,我们的类ListMovieFinder实现了IMovieFinder接口, 实际运行中,是由它来提供数据。
假如这个时候,我们要从数据库中获取数据,怎么办?
非常简单,创建一个类DBMovieFinder继承IMovieFinder接口, 然后注册给Autofac就可以了。 这样程序就非常容易的切换到从数据库中取数据了。
注册相关改动的代码是这样的:
var builder = new ContainerBuilder(); builder.RegisterType<ListMovieFinder>().AsImplementedInterfaces(); //这里注册了DBMovieFinder, 这个类继承IMovieFinder接口。因为它也使用了AsImplementedInterfaces,它会覆盖ListMovieFinder的注册。 builder.RegisterType<DBMovieFinder>().AsImplementedInterfaces(); builder.RegisterType<MPGMovieLister>(); _container = builder.Build();
五、Autofac对程序架构的影响
常见的程序架构大概是: UI层, 业务逻辑层, 持久层(数据层)。
我们可以使用Autofac作为不同层之间的中间人,让UI层依赖于业务逻辑层的抽象接口,业务逻辑层依赖于持久层的接口,而实际运行过程中的实例都由Auotfac来提供。
这样我们就能够解除不同层之间的依赖,将所有的注册类型的操作在一个核心函数或者核心类中实现,那么只要修改这个函数或者类,就能够非常方便的让它们之间的依赖关系发生变化。
比如, 在一个大的项目中,持久层和业务逻辑层是并行开发的,而且是不同团队开发,这个时候业务逻辑开发团队的人在没有持久层代码的情况下,如何开始呢?
我们只要定义好持久层的接口, 业务逻辑团队再写一些Stub类(桩类)来实现这些接口,让这些Stub类来替换真正的持久层,所要做的就只是简单的把这些Stub类型注册到Autofac中就可以了。同时做业务逻辑层的单元测试也非常容易了。
相关推荐
Autofac is an IoC container for Microsoft .NET. It manages the dependencies between classes so that applications stay easy to change as they grow in size and complexity. This is achieved by treating ...
基于.NET的IOC容器 Auto fac的简单设计和使用
Typefac 基于Autofac的TypeScript IoC容器
微软内置ServerCollection和第三方Autofac IOC容器的使用,以及手动实现.(手动实现需要我后续完善,并没有写完整)
Xunit.Ioc 是 XUnit 的扩展,它允许您从依赖注入容器解析测试类。 Autofac 和 Ninject 是开箱即用的,但很容易将它与您的依赖注入容器集成(我们接受拉取请求!)。 为什么这很有用? 能够从容器中解析测试类使...
使用ASP NET MVC 简单的实现了在控制和服务层里面的依赖注入,使用的是Autofac IOC容器
Autofac是Microsoft .NET的。 它管理类之间的依赖关系,以使应用程序随大小和复杂性的增长而保持易于更改的状态。 这是通过将常规.NET类视为。取得包裹您可以通过来获取Autofac。 如果您喜欢冒险,。 。得到帮助在...
在Xamarin中使用Autofac DI / IoC容器。FormsiOS和Android移动应用程序以及UWP Fall Creators Update! 更新 添加了Windows 10 Fall Creators Update的MobileClient.UWP 。 必须安装Windows 10 SDK(16299.15) 。 ...
这是用于PHP的功能齐全的IoC(控制反转)容器。 您可以使用AutoFac或Ninject for .NET等模块类对其进行配置。
autofac是比较简单易用的IOC容器。下面我们展示如何通过json配置文件,来进行控制反转。
本文介绍了NopCommerce中IOC框架Autofac的使用,Autofac是一款IOC框架,比较于其他的IOC框架,如Spring.NET,Unity,Castle等等所包含的,它很轻量级性能上非常高。
Install-Package Our.Umbraco.IoC.Autofac 如果要禁用此容器的支持,可以通过设置此appSetting来禁用。 如果此appSetting不存在,则默认值为'true' Unity支持 Install-Package Our.Umbraco.IoC.Unity 重要提示...
在MVC应用程序中使用Autofac IoC容器来解决依赖关系。 场景包括:控制器,自定义过滤器和视图依赖注入
使用IoC容器是面向对象开发中非常方便的解耦模块之间的依赖的方法。各个模块之间不依赖于实现,而是依赖于接口,然后在构造函数或者属性或者方法中注入特定的实现,方便了各个模块的拆分以及模块的独立单元测试。 在...
此次课程设计中,是对于《软件设计与规范》所学知识与技能的一次综合训练,在此次实验中,我们遵循软件设计规范的规则,使用EntityFramework框架,Autofac依赖注入Ioc容器,工厂模式,单例模式,遵循高内聚,低耦合...
IoC容器注册通过创建IContainerAdapter的实现或对支持的容器使用预制扩展包来实现: Microsoft.DependencyInjection SimpleInjector Autofac 属性注册通过使用Xer.Cqrs.EventStack.Extensions.Attributes包中的...
本项目基于MVC4、Entity Framework 5.0 实体框架、Autofac IOC容器、Postsharp AOP切面框架、AutoMapper 对象映射框架、javascript模块化管理框架 Seajs、DWZ UI界面框架 等 构建了一个代码结构优秀的开发框架,...
工作单位模式储存库模式IOC容器(Autofac) 美人鱼引导程序自动贴图反射吊火下载后,您应该从包管理器控制台中运行以下命令,并选择默认项目:WorkFlowManager.Common PM>更新数据库快乐的设计;) 您可以从查看应用...
简单来说,使用Ioc模式需要两个步骤,第一是把服务注册到容器中,第二是从容器中获取服务,我们一个一个讨论并演化。这里不会考虑使用如Autofac等第三方的容器来代替默认容器,只是提供一些简单实用的小方法用于简化...
BrickController 2 跨平台移动应用程序,用于使用蓝牙游戏手柄控制乐高玩具的创作。支持平台Android 4.3以上iOS 8以上支持的接收器SBrick-普通...使用的第三方库Autofac IOC容器作者伊斯特万·穆尔维(IstvánMurvai)