上节说了一下基本的理论知识,例子可能不太好,不过无所谓了,目的是要让大家明白啥是依赖倒置和依赖注入,目的就达到了,简单一句话,这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的更多相关文章

  1. Docker最全教程之MySQL容器化 (二十四)

    前言 MySQL是目前最流行的开源的关系型数据库,MySQL的容器化之前有朋友投稿并且写过此块,本篇仅从笔者角度进行总结和编写. 目录 镜像说明  运行MySQL容器镜像  1.运行MySQL容器  ...

  2. MVC3+AutoFac实现程序集级别的依赖注入

    1.介绍      所谓程序集级别的依赖注入是指接口和实现的依赖不使用配置文件或硬代码实现(builder.RegisterType<UserInfoService>().As<IU ...

  3. AutoFac (控制反转IOC 与依赖注入DI)

    重要的参考资料http://www.cnblogs.com/xdp-gacl/p/4249939.html 谈谈对Spring IOC的理解 IOC概念(很重要) 项目 先引入AutoFac 和Aut ...

  4. 使用Spring AOP实现业务依赖解耦

    Spring IOC用于解决对象依赖之间的解耦,而Spring AOP则用于解决业务依赖之间的解耦: 统一在一个地方定义[通用功能],通过声明的方式定义这些通用的功能以何种[方式][织入]到某些[特定 ...

  5. 依赖注入(二)Autofac简单使用

    Autofac简单使用 源码下载传上源码,终于学会传文件了. 首先 还是那句话:“不要信我,否则你死得很惨!”. C#常见的依赖注入容器 IoC in .NET part 1: Autofac IoC ...

  6. AutoFac实现程序集级别的依赖注入

    1.介绍      所谓程序集级别的依赖注入是指接口和实现的依赖不使用配置文件或硬代码实现(builder.RegisterType<UserInfoService>().As<IU ...

  7. 5个步骤,教你瞬间明白线程和线程安全.md

    记得刚来杭州面试的时候,有一家公司的技术总监问了我这样一个问题:你来说说有哪些线程安全的类?我心里一想,这我早都背好了,稀里哗啦说了一大堆. 他又接着问:那你再来说说什么是线程安全?--然后我就GG了 ...

  8. 控制反转IOC与依赖注入DI - 理论篇

    学无止境,精益求精 十年河东十年河西,莫欺少年穷 昨天是五一小长假归来上班的第一天,身体疲劳,毫无工作热情.于是就看看新闻,喝喝茶,荒废了一天 也就在昨天,康美同事张晶童鞋让我学习下IOC的理论及实现 ...

  9. Android开发之手把手教你写ButterKnife框架(二)

    欢迎转载,转载请标明出处: http://blog.csdn.net/johnny901114/article/details/52664112 本文出自:[余志强的博客] 上一篇博客Android开 ...

随机推荐

  1. 【BZOJ 2321】 [BeiJing2011集训]星器

    Description Magic Land上的时间又过了若干世纪…… 现在,人们谈论着一个传说:从前,他们的祖先来到了一个位于东方的岛屿,那里简直就是另外一个世界.善于分析与构造的Magic Lan ...

  2. 隐藏和显示效果js动画

    <div id='ctt' style='margin-left: 50px; color: white'>             <input type="button ...

  3. s3c2440之cache

    cache高速缓冲存储器注意与块设备页高速缓存进行区别,一个是硬件的实现一个是软件的实现,块设备页高速缓存. s3c2440/s3c2410里面主要有一个arm920t的核,但同时包含几个协处理器,协 ...

  4. (转载)shell日志分析常用命令

    shell日志分析常用命令总结 时间:2016-03-09 15:55:29来源:网络 导读:shell日志分析的常用命令,用于日志分析的shell脚本,统计日志中百度蜘蛛的抓取量.抓取最多的页面.抓 ...

  5. 1020: [SHOI2008]安全的航线flight - BZOJ

    Description在设计航线的时候,安全是一个很重要的问题.首先,最重要的是应采取一切措施确保飞行不会发生任何事故,但同时也需要做好最坏的打算,一旦事故发生,就要确保乘客有尽量高的生还几率.当飞机 ...

  6. IOS 数组分组 Grouped NSArray

    NSMutableSet *set=[NSMutableSet set]; [_list enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BO ...

  7. js验证中英文

    // 验证中英文 function check_en_ch(_value){ var reg_en_num = /^[0-9A-Za-z\'\"\,\.\!\?\:\s|“|”|‘|’|!| ...

  8. Matlab求极限

    matlab求极限(可用来验证度量函数或者隶属度函数)可用来验证是否收敛,取值范围等等. 一.问题来源 搜集聚类资料时,又看到了隶属度函数,没错,就是下面这个,期间作者提到m趋于2是,结果趋于1,我想 ...

  9. FireFly 服务端 Unity3D黑暗世界 客户端 问题

    启动服务端成功截图: 连接成功截图: 测试服务端是否启动成功: 在Web输入:http://localhost:11009/  按回车 (查看cmd启动的服务端 是否多出如下显示) 服务端启动成功.P ...

  10. SDUT2191Calendar

    http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2191 题意:给你两个年月日,让你算出其中经历了 ...