按需分配,共创和谐社会的钥匙:依赖注入
滚滚长江东逝水,浪花淘尽英雄。一代代的先辈的努力才造就我们的今天,细数历史的进步会让人深感受益良多。
本系列文将着重比对历史的发展和控制反转产生的关系,此文为引导文,主要介绍依赖注入,之后会有一系列文章来分析各种实现方式,希望大家拍砖。
[小九的学堂,致力于以平凡的语言描述不平凡的技术。如要转载,请注明来源:小九的学堂。cnblogs.com/xfuture]
历史的发展
远古母系氏族,每个人都是一个独立的个体,需要什么工具就需要自己去打磨一件工具,自己需要了解所有的流程才能生存。比如打猎,从前期准备绳索,尖木,到中期做陷阱,后期收成,都需要了解的非常透彻。对应编程中便是new 绳索(),new 尖木(),new 陷阱(),new X()。实例化所有需要的资源,然后再进行逻辑流程。
人类逐渐在进步,工业革命的来袭,改变了整个社会的结构。人再不需要了解所有的流程,只需要去一个工厂或者采购平台,输入自己想要的东西,便能得到。对应编程中便是工厂模式,需要一个静态工厂类,一个抽象产品类型的类,一个你想拿到的可以具象化的产品类,从此便进入了全民淘宝年代,需要什么购买什么。
当你为了修一个顶楼的灯泡购买了梯子,但当修好后,如何处理这个梯子便成了难题,扔掉不舍,不扔去卖二手又很麻烦。这时候就需要我们的主角:和谐社会登场了!主张不铺张不浪费,这便是一种回收机制,你需要它只需要说一声,秒秒钟就到你手里,你也不需要知道他来自哪里。不需要了你也不用管,我直接秒秒钟再变走。是不是有一种魔术的感觉?这便是依赖注入!依赖注入解除了对象和对象的依赖关系,需要其他对象时候,会有外部直接注入给你,而你不需要。对象符合OCP原则(对外扩展开放,对修改关闭), 容器负责所有关系匹配。在此层,容器便是这个社会的规则,而对象只需要关心自己所完成的一部分就好。轻松惬意!
依赖注入:Dependency Injection
从起始的new,new,new到后来的多态,面向接口编程,匹配协议规定的规则,直到按需分配,外部注入的控制反转依赖注入。实际上就和人类进步的逻辑是一样的,目的就是为了让工作分配的更明确,更效率,彼此依赖越来越少。依赖注入隔离了变化,让之不会影响不变的对象部分。依赖注入实际上是很多原则的合体。多态使类不再依赖其他服务类,只需要接口,实现了OCP(对外扩展开放,对修改关闭)。为了不需要实例具体的服务类,就需要定义注入点(接口),容器来进行服务,实现注入。
注入容器:Container
依赖注入需要一个容器来储存所有的资源,根据你的需要按需分配,进行注入。依赖注入还有个名字叫控制反转,就是大家经常说的IOC。
轻量级的有Unity Container, Autofac, Spring等,重量级有EJB, 还有游离在轻重之间的是JBoss等。之后系列文会详细介绍几种常用的,比如container,autofac,ejb。
由于本人经常使用prism,orchard,故而会更详细介绍container和autofac,也会把使用心得更多分享给大家。
基本技术:反射
IOC是工厂模式的升华,最基本的技术是“反射”。根据一个注入的匹配表或者规则,来进行灵活的注入。
注入规则:
1. xml来进行配置。
Spring使用xml文件来进行beans的匹配。好处在于完全抽离了代码层次,在xml进行配置,用字符串来进行反射注入。但坏处就是xml的维护,需要一个很好的IDE
2.Assembly注入,class,interface匹配。在.NET里个人比较喜欢这种。
var builder = new ContainerBuilder(); builder.RegisterGeneric(typeof(Dal<>)).As(typeof(Idal<>)).InstancePerDependency(); builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)).InstancePerDependency(); builder.Register(c=>new PersionBll((IRepository<Persion>).Resolve(typeof(IRepository<Persion>)))); builder.Register(c => new CustomBll((IRepository<Custom>) c.Resolve(typeof(IRepository<Custom>)))); var container = builder.Build()
这里只大概列出一些例子。具体会有详细介绍在系列篇后篇。
注入方法:
1.接口注入,2.构造函数注入,3.属性注入
开碟小菜(不使用容器,仅使用接口和实现类来展现依赖注入的基本逻辑)
场景:家里很多电视,有时候这个可以用,有时候那个可以用。希望能在替换的时候,个人这边是不需要更改什么的,依然是拿起遥控器就能看电视,不管是哪个。
解决方案:(接口注入)
// 创建实现看电视功能的接口 public interface ITvProvider { void WatchTv(); } // 创建一个TV的实体类,继承ITvProvider,实现其WatchTv方法。 public class KonkaTv:ITvProvider { public void WatchTv() { // 实现看康佳电视功能的逻辑代码 } } // 创建一个注入用的接口,实现类似容器/XML链接对象匹配的功能 public interface ITvInjecter { void InjectTv(ITvProvider tvProvider); } // 创建一个看电视的控件,继承ITvInjecter(容器时则是继承类似IDepency这种可以拿到容器, 这里是不使用容器的方法) public Control WatchTvControl:ITvInjecter { private ITvProvider _tvProvider; // 若使用容器,则在构造函数里既可以实现注入,不用手工来写注入方法。 public void InjectTv(ITvProvider tvProvider) { _tvProvider = tvProvider } public WatchTvControl() { // 注入完成后便可以使用其watchtv方法 _tvProvider.WatchTv(); } } // 主程序,代码层次实现注入并调用 public partial class App { private void Application_Startup(object sender, StartupEventArgs e) { ITvProvider tvProvider = new KonkaTv(); WatchTvControl watchTvControl = new WatchTvControl(); watchTvControl.InjectTv(tvProvider); } }
通过这样的调用,就可是实现解耦和。当你想要更换Tv的时候只需要在主程序中更换就好,其余功能模块则完全不需要更改。(容器则是注入其他Tv实体类就好)
希望大家点赞关注和拍砖。个人是在做.net,比较擅长使用prism和orchard(非常宏大的设计模式集合的CMS框架,分布式网络的福音),对依赖注入的好处感受也比较深刻一些.总之希望大家持续关注。我也会努力提升自己来写出更好文章丰富这个小学堂的,希望每项技术都能映射到现实的例子,其实编程就是人生啊!