通过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开 ...
随机推荐
- 如何将无线路由器作为交换机,将光猫(路由器A)分出来的一条网线接到自家另一台路由器B上,最大化利用网络资源
从隔壁邻居只接了一条网线过来,由于无线网络的距离有限,不能覆盖到家里任何角落,然而,我又想家里一台台式电脑和无线设备都能够连接wifi进行上网。 摸索了一个上午,知道将家里的无线路由器B当作一个无线A ...
- (转)PHP中的 抽象类(abstract class)和 接口(interface)
转自:http://blog.csdn.net/sunlylorn/article/details/6124319 一. 抽象类abstract class 1 .抽象类是指在 class 前加了 a ...
- (转)sqlserver游标概念与实例全面解说
首先声明:该文章转自http://www.cnblogs.com/wudiwushen/archive/2010/03/30/1700925.html 的博客 引言 我们先不讲游标的什么概念,步骤 ...
- eclipse *.vm 文件,语法高亮
eclipse *.vm 文件,语法高亮按如下方式不起作用,原因不明.设置文件打开时使用的编辑器General>>Editors>>File Associations 下述方试 ...
- 简单3d RPG游戏 之 002 生命条(二)
在游戏中,游戏人物的血条可能会因为受伤或吃血瓶而长度变化,所以需要将血条的长度单独提出来作为一个变量,方便直接修改数值. public float healthBarLength; 改变生命值函数如下 ...
- 3150 Pibonacci数 - Wikioi
题目描述 Description 你可能听说过的Fibonacci数和圆周率Pi. 如果你让这两个概念合并,一个新的深奥的概念应运而生:Pibonacci数. 这些数可以被定义为对于x>=0: ...
- HDFS 的可靠性
HDFS 的可靠性主要有一下几点: 冗余副本策略 机架策略 心跳机制 安全模式 效验和 回收站 元数据保护 快照机制 1.冗余副本策略 可以在hdfs-site.xml中设置复制因子指定副本数量 所有 ...
- 用CImage类来显示PNG、JPG等图片
系统环境:Windows 7软件环境:Visual Studio 2008 SP1本次目的:实现VC单文档.对话框程序显示图片效果 CImage 是VC.NET中定义的一种MFC/ATL共享类,也是A ...
- ****JFinal 部署在 Tomcat 下推荐方法
首先明确一下 JFinal 项目是标准的 java web 项目,其部署方式与普通 java web 项目没有任何差别.Java Web 项目在 Tomcat 下部署有一些不必要的坑需要避免 经常有人 ...
- ***CI异常记录到日志:CodeIgniter中设计一个全局exception hook
在CodeIgniter中,当发生异常时,经常要通知系统管理员,因此有必要在全局的高度上 捕捉异常,因此可以写一个hook, 比如在config目录的hook.php中,加入: $hook['pre_ ...