IOC和DI(控制反转和依赖注入)通俗解析

本文深入探讨了控制反转(IoC)与依赖注入(DI)的概念,解释了两者的关系及其实现方式。通过对比传统类间直接调用的方式,阐述了依赖注入如何降低代码耦合度,实现模块间的解耦,提升软件的可维护性和灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

控制反转 跟依赖注入,这两个概念很多人搞不清楚,越研究越模糊,研究了之后不知道在哪里用?

一:什么是控制反转

IoC——Inversion of Control  控制反转
 DI——Dependency Injection   依赖注入 

1:控制反转  不是一种技术,是一种思想

2:依赖注入是 控制反转的 一种具体实现方式,

要想理解上面两个概念,就必须搞清楚如下的问题:

  • 参与者都有谁?
  • 依赖:谁依赖于谁?为什么需要依赖? 
  • 注入:谁注入于谁?到底注入什么?
  • 控制反转:谁控制谁?控制什么?为何叫反转(有反转就应该有正转了)?

 

二:那么控制反转跟依赖注入 是干什么的,为什么要有这两个概念?

背景:

做过项目的人,尤其是ERP那样的臃肿的项目的时候,项目迭代了无数次,人员换了一批又一批的时候,新接手的人第一眼看到代码,首先是:100个鄙视,这么烂的代码也写的出来。然后准备去优化,要显示一下自己的水平,准备去修改一点点写的功能的时候发现,这里不改,那里也不能改,补好了一个bug,然后出现了10给bug。这就是项目的维护成本有多高  就可想而知了。

 这个时候就知道天天喊得口号:低耦合 高内聚  真的不是喊口号喊出来的。

耦合度高表现在哪里? 

               1:类与类之间直接调用,直接在A类中直接New一个对象 ,然后调用里面的方法,属性,等

               2:项目直接dll引用 (C#)/ 包的导入(Java)  直接引用dll,dll里面的类直接new对象。

               3:业务之间的互相调用,逻辑不清晰 等等

那么我们如何解决呢?

               那有没有办法,在调用类里面的代码的时候,不直接new对象呢?完全脱离对象实例化呢?答案是  :有办法

这里就需要用到 依赖注入:

                原先A类调用B类是: 在A类的代码里面实现:B b=new B(); 然后  b.方法/属性/成员变量 等

               用依赖注入怎么处理呢?那就不需要new对象了,只需要用对象继承的接口直接去调用接口里面的方法,整个过程中没有任何关于B类的实例化:

我们知道了依赖注入是干什么的了。目的就是 解耦。实现代码的各个模块之间,各个类之间的分离。

 

        

三:依赖注入的三种方式:

      1、属性注入 2、构造器注入 3、方法注入

 

 

四:依赖注入:是一种实现控制反转的过程,这个过程如何实现呢?

这里我们需要了解一些技术:

例如1:C#  里面需要了解Ninject 容器   Unity容器    /java里面的Spring容器   

这里具体各个容器的具体实现,后面有时间再写,这里写一些依赖注入的思想:

相当于有一个大的容器。A类 ,B类 都可以事先把对象通过  接口注入   的方法注入到容器中,就相当于已经实例化了,谁要用谁来直接拿。所以这里依赖注入的一般C#都默认放在:Global.asax 文件中,目的是为了不影响后面的性能。这样在项目启动的时候就已经启动了,不会对后面的业务有任何的性能影响。

以Ninject 为示例:以Factory方式依赖注入

首先1:把接口需要通过一定的方式注入进容器:

前面的一些是ninject内部需要注入的,后面的访问日志,首页 就是业务上需要注入的接口。

          kernel.Bind<IDisposable>().To<CL.Service.Disposable>();
            kernel.Bind<DB.Interfaces.IDatabaseFactory>().To<DB.Service.DatabaseFactory>();
            kernel.Bind<DB.Interfaces.IHttpRuntimeWrapper>().To<DB.Service.HttpRuntimeWrapper>();
            kernel.Bind<IDatabaseFactory>().To<CL.Service.DatabaseFactory>();
            kernel.Bind(typeof(IRepository<>)).To(typeof(CL.Service.RepositoryBase<>));
            kernel.Bind(typeof(DB.Interfaces.IRepository<>)).To(typeof(DB.Service.RepositoryBase<>));
            //访问日志
            kernel.Bind<CL.Interfaces.VisitLog.IVisitLogRepository>().To<CL.Service.VisitLog.VisitLogRepository>();
            //首页banner
            kernel.Bind<CL.Interfaces.Banner.IBannerRepository>().To<CL.Service.Banner.BannerRepository>();
            //热门城市
            kernel.Bind<CL.Interfaces.Search.IHotCityRepository>().To<CL.Service.Search.HotCityRepository>();

 

2:然后在Global.asax 文件中提前注入完成。

 #region 提前注入步骤
            //访问日志
            RepositoryFactory.VisitLogRepository = RepositoryService.GetService<CL.Interfaces.VisitLog.IVisitLogRepository>();
            //首页banner
            RepositoryFactory.BannerRepository = RepositoryService.GetService<CL.Interfaces.Banner.IBannerRepository>();

 

3:调用:直接这样调用各种接口里面的方法。

    RepositoryFactory.WeAppCouponActivity.InsertWeAppCouponActivity(rel.WeChatMemberBindInfo.cardNo, m676Info.phone, "WeChatApplet");

 

后面再详细讨论 各个容器之间的依赖注入方式以及如何实现调用。网上最多的案例就是spring的依赖注入。

 

五:后续...

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值