通过autofac教你彻底明白依赖解耦(二)理论结合实践 - 大侠.Net
上节说了一下基本的理论知识,例子可能不太好,不过无所谓了,目的是要让大家明白啥是依赖倒置和依赖注入,目的就达到了,简单一句话,这2玩意都是用来解耦合的。
不过依赖倒置这个词哥哥真不敢苟同,哥哥来个颠覆的说法,我说这是依赖正置。
因为本来就应该是上层依赖上层嘛,低层也应该依赖上层,但是由于程序语言的原因,导致代码和实际完全不符合,搞得抽象经常依赖具体,具体更是依赖具体。
体现在代码中就是接口中关联类型,类型中也关联类型。完全反了。所以我们呢要让他正常起来,让接口只依赖接口,类也只依赖接口,这个实际比较相符合,所以哥哥我叫他依赖正置。
说了依赖正置,接下来再说说控制反转IOC,我们要说的autofac就是是IOC的一个框架。
啥是控制反转吧?你想啊,我们一般写代码是这样:举个去死的栗子
public interface IPerson
{
void GoToHell(IPlace hell);
} public class CodeFarmer : IPerson
{
public void GoToHell(IPlace hell)
{
hell.Accept(this);
}
} public interface IPlace
{
void Accept(IPerson person);
} public class Hell : IPlace
{
public void Accept(IPerson person)
{
// do sth..
}
} public class God
{
public void Do()
{
IPerson you = new CodeFarmer();
you.GoToHell(new Hell());
}
}
看,咱们是没有违反基本的DIP原则吧,基本都是依据接口编程的。
但是还是老话,在客户端god哪里还是有问题,他要你去死,还必须要知道hell的创建逻辑,god表示你这东西简直不能用,我只是要你去死而已呀,我还要给你指明通向hell的道路?
god表示很忙!把hell的初始化放在person 中如何?可以,不是有句话说,人一出生,就是坐上了通往死亡的列车,谁说的?好像是我自己!!
public interface IPerson
{
IPlace Hell { get; set; } void GoToHell();
} public class CodeFarmer : IPerson
{
public IPlace Hell { get; set; } public CodeFarmer()
{
Hell = new Hell();
} public void GoToHell()
{
Hell.Accept(this);
}
} public interface IPlace
{
void Accept(IPerson person);
} public class Hell : IPlace
{
public void Accept(IPerson person)
{
// do sth..
}
} public class God
{
public void Do()
{
IPerson you = new CodeFarmer();
you.GoToHell();
}
}
这样,你自己往hell走就行了,god表示我是老板,我只发指令给你,具体的路线你自己去搞!
但是CodeFarmer就不忙?最后要死了都要自己找路去死?简直不能干,这个行业!那怎么办?这个new Hell()的部分放在那里好呢?
其实这个就是我们程序里面常见的问题,依赖的具体对象创建到哪里注入比较好呢?好像哪里都不符合逻辑!
那既然这样,那创世者说我发个公告牌如何?我就告诉你,这个地方有个公告板,里面告诉你了地狱怎么走,你要去的话,你自己去看看就得了,没必要自己摸路。
public interface IPerson
{
void GoToHell(IPlace hell);
} public class CodeFarmer : IPerson
{
public void GoToHell(IPlace hell)
{
hell.Accept(this);
}
} public interface IPlace
{
void Accept(IPerson person);
} public class Hell : IPlace
{
public void Accept(IPerson person)
{
// do sth..
}
} public class God
{
public void Do()
{
IPerson you = InfoBoard.PlaceInfo["person"];
you.GoToHell(InfoBoard.PlaceInfo["hell"]);
}
} public class InfoBoard
{
public static Dictionary<string, IPlace> PlaceInfo = new Dictionary<string, IPlace>(); static InfoBoard()
{
PlaceInfo.Add("hell", new Hell());
PlaceInfo.Add("person", new CodeFarmer()); }
}
这样,不管是在god中,还是在codefamer中,直接可以使用InfoBoard.PlaceInfo["hell"]来去到通往地狱的路,有指明灯多好啊。
比较官方的语言:应用控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用,传递给它。也可以说,依赖被注入到对象中。所以,控制反转是,关于一个对象如何获取他所依赖的对象的引用,这个责任的反转。
怎么样,真jb难懂是吧?
我就给你翻译成人类能懂的话,你不是要面向接口编程吗?你接口,你TM最后总要有new的时候吧?你一旦new了,一个对象和另一个对象实际上的强依赖是不是产生了?既然这样,那我们都不new,由一个在程序看来虚无缥缈的地方保存有所有抽象类和接口对象的具体实现。从哪里取就行了,这样可好?那我和你永远只关心接口就行了
就像上面的栗子中,不管是god中还是codefarmer还是hell中,是不是没有任何创建彼此的代码?是不是这个耦合彻底解除了(或者说是转移了到InfoBoard中了,便于集中管理,前文有提到)?
我告诉你,这个就是一个最简单的ioc容器。控制反转,我还是那句话,我自己给他定义一个名词,控制转移比较好!谈不上什么正反,这个!!
那有的同学问,你TM这用你昨天讲的反射不是可以达到一样的效果?你说你玩这个,你玩他有什么用啊?我想说的是,就是可以达到一样的效果!!但是,我只多说一个词,性能!其他的我不多讲。如果你的系统没那么多jjyy的性能的事情,完全用反射就行了
那IOC容器就这样就行了?肯定不行啊,举个栗子:
我们用ado访问数据库
public class InfoBoard
{
public static Dictionary<string, object> PlaceInfo = new Dictionary<string, object>(); static InfoBoard()
{
PlaceInfo.Add("conn", new SqlConnection("connect string"));
PlaceInfo.Add("comm", new SqlCommand("SELECT *****************", InfoBoard.PlaceInfo["conn"] as SqlConnection));
}
}
看如果我执行一次comm后实际上SqlConnection如果释放了,这个comm是不是没用了?
如果要保证comm有效这个SqlConnection是不是不能释放,这2种方式都不是我们想要的,所以,你必须要有个对象过期策略,和非托管资源的释放问题。
这个SqlConnection根被就不能写在静态构造中,实际的ioc框架还会遇到很多问题,这就是一个autofac代码茫茫多的原因
西门子哪个广告语,我一直拿着用,精于心,简于形,为了一点点的性能问题,背后的工作是巨大的,还好有现成的框架帮我们做了很多事情。
下载,引用,或者通过NUGET方式获取框架,这些不多说。正常人都能搞定
using Autofac; public interface IPerson
{
IPlace Hell { get; set; }
string Name { get; set; }
void GoToHell();
} public class CodeFarmer : IPerson
{
public string Name { get; set; }
public IPlace Hell { get; set; } public CodeFarmer(IPlace Hell)
{
this.Hell = Hell;
} public void GoToHell()
{
Hell.Accept(this);
}
} public interface IPlace
{
void Accept(IPerson person);
} public class Hell : IPlace
{
public void Accept(IPerson person)
{
Console.WriteLine(person.Name+" is gonna die");
Console.ReadKey();
}
} class Program
{ private static IContainer Container { get; set; } static void InitApplication()
{
var builder = new ContainerBuilder();
builder.RegisterType<Hell>().As<IPlace>();
builder.RegisterType<CodeFarmer>().As<IPerson>();
Container = builder.Build();
} static void Main(string[] args)
{
InitApplication();
var aSadMan = Container.Resolve<IPerson>();
aSadMan.Name = "hard worker";
//var goodPlace = Container.Resolve<IPlace>();
aSadMan.GoToHell();
}
}
private static IContainer Container { get; set; }
有个Container容器有没有?
builder.RegisterType<Hell>().As<IPlace>();
builder.RegisterType<CodeFarmer>().As<IPerson>();
往容器里面加东西有没有?
var aSadMan = Container.Resolve<IPerson>();
从容器里面取东西有没有?
那有的人就问了,你CodeFarmer里面的IPlace对应的hell是怎么实例化的?CodeFarmer的构造函数都没看到调用啊?
这里就是所谓的构造函数注入,你只需要知道,这样写,然后解析他的上层类IPerson,这个hell是自动实例化的,够造函数自动被调用了,里面的参数自动被解析成hell,因为你前面有往container中registertype过,这样就行了,是不是很强大呢?
public IPlace Hell { get; set; }
public CodeFarmer(IPlace Hell)
{
this.Hell = Hell;
}
如果Hell的构造里面还要注入其他的依赖,这个解析可以一直嵌套下去,无论有多少层,只要你从最上面的入口做了类似
var aSadMan = Container.Resolve<IPerson>();
行了,先说到这,下回再扯吧,欢迎拍砖,往死里拍,上文有个错误,把依赖倒置说成了DI应该是dip,汗!因为,我写这些,例子都是我自己随便想的,基本上时间也仓促,难免有不完全对的地方,但是核心我都说明白了的,大家有问题可以提出来探讨,就是不要直接说有问题,但是不说明问题再那里,这样就没意思了!基本我都不会检查第2遍。人都说第一想到的东西都是最真实和正确的,有没有?
通过autofac教你彻底明白依赖解耦(二)理论结合实践 - 大侠.Net的更多相关文章
- Docker最全教程之MySQL容器化 (二十四)
前言 MySQL是目前最流行的开源的关系型数据库,MySQL的容器化之前有朋友投稿并且写过此块,本篇仅从笔者角度进行总结和编写. 目录 镜像说明 运行MySQL容器镜像 1.运行MySQL容器 ...
- MVC3+AutoFac实现程序集级别的依赖注入
1.介绍 所谓程序集级别的依赖注入是指接口和实现的依赖不使用配置文件或硬代码实现(builder.RegisterType<UserInfoService>().As<IU ...
- AutoFac (控制反转IOC 与依赖注入DI)
重要的参考资料http://www.cnblogs.com/xdp-gacl/p/4249939.html 谈谈对Spring IOC的理解 IOC概念(很重要) 项目 先引入AutoFac 和Aut ...
- 使用Spring AOP实现业务依赖解耦
Spring IOC用于解决对象依赖之间的解耦,而Spring AOP则用于解决业务依赖之间的解耦: 统一在一个地方定义[通用功能],通过声明的方式定义这些通用的功能以何种[方式][织入]到某些[特定 ...
- 依赖注入(二)Autofac简单使用
Autofac简单使用 源码下载传上源码,终于学会传文件了. 首先 还是那句话:“不要信我,否则你死得很惨!”. C#常见的依赖注入容器 IoC in .NET part 1: Autofac IoC ...
- AutoFac实现程序集级别的依赖注入
1.介绍 所谓程序集级别的依赖注入是指接口和实现的依赖不使用配置文件或硬代码实现(builder.RegisterType<UserInfoService>().As<IU ...
- 5个步骤,教你瞬间明白线程和线程安全.md
记得刚来杭州面试的时候,有一家公司的技术总监问了我这样一个问题:你来说说有哪些线程安全的类?我心里一想,这我早都背好了,稀里哗啦说了一大堆. 他又接着问:那你再来说说什么是线程安全?--然后我就GG了 ...
- 控制反转IOC与依赖注入DI - 理论篇
学无止境,精益求精 十年河东十年河西,莫欺少年穷 昨天是五一小长假归来上班的第一天,身体疲劳,毫无工作热情.于是就看看新闻,喝喝茶,荒废了一天 也就在昨天,康美同事张晶童鞋让我学习下IOC的理论及实现 ...
- Android开发之手把手教你写ButterKnife框架(二)
欢迎转载,转载请标明出处: http://blog.csdn.net/johnny901114/article/details/52664112 本文出自:[余志强的博客] 上一篇博客Android开 ...
随机推荐
- html 页面 ajax 方法显示遮罩
showLoading.css 样式: ;;list-style-type:none;} a,img{;} .overlay{;;;;;width:100%;height:100%;_padding: ...
- Eclipse中设置作者日期等信息
在使用Eclipse 编写Java代码时,自动生成的注释信息都是按照预先设置好的格式生成的,例如其中author 的属性值. 我们可以在Eclipse 中进行设置自己希望显示的信息. 现在看看如何修改 ...
- String声明为NULL和""的区别
代码虐我千百遍,我待代码如初恋. String 声明为 NULL 则声明了一个变量不指向任何一块地址,则 length()会出现错误. 声明为"",则是一个长度为0的字符串.
- HTTP verb的安全性和幂等性
Http协议规定了不同方法的安全特性和幂等特性,作为服务提供者的服务器必需为客户端提供这些特性. 安全性,仅指该方法的多次调用不会产生副作用,不涉及传统意义上的“安全”,这里的副作用是指资源状态.即, ...
- PAT-乙级-1008. 数组元素循环右移问题 (20)
1008. 数组元素循环右移问题 (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 一个数组A中存有N(N>0)个整数,在不允 ...
- DWR
DWR(Direct Web Remoting)是一个用于改善web页面与Java类交互的远程服务器端Ajax开源框架,可以帮助开发人员开发包含AJAX技术的网站.它可以允许在浏览器里的代码使用运行在 ...
- Hadoop之RPC
Hadoop的RPC主要是通过Java的动态代理(Dynamic Proxy)与反射(Reflect)实现,代理类是由java.lang.reflect.Proxy类在运行期时根据接口, ...
- 【mysql的设计与优化专题(1)】ER图,数据建模与数据字典
需求分析是做项目中的极为重要的一环,而作为整个项目中的'血液'--数据,更是重中之重.viso,workbench,phpmyadmin等软件可以帮我们更好的处理数据分析问题. ER图 E-R方法是& ...
- 【转】windows c++获取文件信息——_stat函数的使用
_stat函数的功能 _stat函数用来获取指定路径的文件或者文件夹的信息. 函数声明 int _stat( const char *path, struct _stat *buffer ); 参数: ...
- IE Web 开发支持将迁移到 StackOverflow
http://stackoverflow.com/questions/tagged/internet-explorer