上节说了一下基本的理论知识,例子可能不太好,不过无所谓了,目的是要让大家明白啥是依赖倒置和依赖注入,目的就达到了,简单一句话,这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. (转)《深入理解java虚拟机》学习笔记3——垃圾回收算法

    Java虚拟机的内存区域中,程序计数器.虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭:栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构 ...

  2. SQL Server 2008 的gis函数

    居然不知道sql有gis函数,孤陋寡闻了 https://msdn.microsoft.com/zh-cn/library/bb933904.aspx   STContains(geometry 数据 ...

  3. 编辑器&IDE中适合程序员的字体

    adobe的免费字体 source Code Pro

  4. springmvc整合redis架构搭建实例

    新换环境,又有新东西可以学习了,哈皮! 抽空学习之余看了一下redis,个人对Springmvc的爱是忠贞不渝,所以整理了一下Springmvc整合redis的环境搭建.分享学习. 第一步: 创建ma ...

  5. 对jQuery.extend()方法的分析

    jQuery.extend方法是我们常用的方法,也是jQuery源码中的基础方法.它的主要作用是:将一个或多个“源对象”合并到一个“目标对象”中,并返回目标对象.它主要有三种表现形式: a.jQuer ...

  6. uva 10986

    ford 超时  使用优先队列的Dijkstra 算法 //#include <cstdio> //#include <cstring> //#include <algo ...

  7. 安装Redis完整过程

    概述    首先报告一下我系统的版本: [root@firefish init.d]# cat /etc/issue 系统版本信息如下: 引用 CentOS release 6.4 (Final) K ...

  8. SQL四种语言:DDL,DML,DCL,TCL

    1.DDL(Data Definition Language)数据库定义语言statements are used to define the database structure or schema ...

  9. Java Web开发 之小张老师总结EL、JSP、Servlet变量

    EL 11 JSP 9 Servlet JSP类别 pageContext pageContext * 作用域 pageScope pageContext.getAttribute() * reque ...

  10. 两个基于C++/Qt的开源WEB框架

    1.tufao 项目地址: https://github.com/vinipsmaker/tufao 主页: http://vinipsmaker.github.io/tufao/ 介绍: Tufão ...