.NET控制反转(IOC)和依赖注入(DI)

一、前言
理解这些概念对于我来说有些非常困难。 但实际上它们非常简单,我们在日常编码中使用它。
今天,我想谈谈编码中依赖性的问题以及控制反转(IOC)和依赖注入(DI)想要说些什么。 本文面向渴望了解最重要原则,但在实现方面有点困惑的读者。

二、疑问点
1. 什么是控制反转(IOC)?。
2. 什么是依赖注入(DI)?。
3. 实现依赖注入的方法
4. 实施这一原则的优点

三、控制反转IOC
通过下面的例子讲解:在我们大学日常,我们有时会举办各种活动,有时甚至是无聊的讲座,考虑并回忆大学的日常生活,让我们尝试将大学和活动与控制反转(IOC)联系起来。

   public class College
    {

        private TechEvents _events = null;

        public College()
        {
            _events = new TechEvents();
        }

        public void GetEvents()
        {
            _events.LoadEventDetail();
        }
    }

    public class TechEvents
    {
        public void LoadEventDetail()
        {
            Console.WriteLine("Event Details");
        }
    }

上面 College 类的作用是创建 TechEvents 对象。

假设我有一个类为Colleage,另一个类为TechEvents。 正如您在上面所看到的,可能会出现许多问题:

  1. 这两个类彼此紧密耦合。 我不能没有TechEvents的College,因为在College构造器中创建了一个TechEvents对象。
  2. 如果我对TechEvents进行任何更改,我需要编译,或者你也可以说更新College类。
  3. College 控制 Events 的创建。College 知道有组织的单一 Event。 如果有任何特定 event 像足球活动或Party活动被组织,则需要对 College 类进行更改,因为College直接引用Events。

  现在我需要以某种方式解决这个问题,否则我们将无法在大学里举办任何其他活动。

  解决这个问题的方法可能是将事件组织的控制权转移到其他地方。我们称之为控制反转(IOC),将控制权转换为其他实体,而不是直接在 College 组织 Event。什么反转控制原理说?

 换句话说,主要类不应该具有聚合类的具体实现,而应该依赖于该类的抽象。 College类应该依赖于使用接口或抽象类的TechEvents类抽象

   /// <summary>
    /// 创建一个接口为了实现抽象
    /// </summary>
    public interface IEvent
    {
        void LoadEventDetail();
    }

    /// <summary>
    /// 所有类型事件活动类应该实现 IEvent
    /// </summary>
    public class TechEvent : IEvent
    {
        public void LoadEventDetail()
        {
            Console.WriteLine("Technology Event Details");
        }
    }

    /// <summary>
    /// 所有类型事件活动类应该实现 IEvent
    /// </summary>
    public class FootballEvent : IEvent
    {
        public void LoadEventDetail()
        {
            Console.WriteLine("Football Event Details");
        }
    }

    /// <summary>
    /// 所有类型事件活动类应该实现 IEvent
    /// </summary>
    public class PartyEvent : IEvent
    {
        public void LoadEventDetail()
        {
            Console.WriteLine("Party Event Details");
        }
    }

    public class College
    {
        private IEvent _events = null;

        /// <summary>
        /// College 构造器提示说需要一个活动事件
        /// </summary>
        /// <param name="ie"></param>
        public College(IEvent ie)
        {
            _events = ie;
        }

        public void GetEvents()
        {
            _events.LoadEventDetail();
        }
    }

四、依赖注入(DI)

      可以使用依赖注入(DI)来完成 IOC 。 它解释了如何将具体实现注入到使用抽象的类中,换句话说就是内部的接口。 依赖注入的主要思想是减少类之间的耦合,并将抽象和具体实现的绑定移出依赖类

简单来说,DI就是一个对象如何去知道那些被抽象的其他依赖对象。实现依赖注入主要有4种方法。

1、构造函数注入

  public class College
    {
        private IEvent _events = null;

        /// <summary>
        /// College 构造器提示说需要一个活动事件
        /// </summary>
        /// <param name="ie"></param>
        public College(IEvent ie)
        {
            _events = ie;
        }

        public void GetEvents()
        {
            _events.LoadEventDetail();
        }
    }

如上所示,事件对象由构造函数注入,使其保持抵耦合。 College类将完成他的工作,如果它想获取与事件相关的详细信息,它将根据他想要调用的事件在构造函数中调用它。

College coll = new College(new FootballEvent()); 

除了这个优势,另一个优点是,如果事件有任何变化或添加了更多事件,那么College不需要关心这一点。

2、方法注入

class College  
{  
        private IEvent _events;  
        public void GetEvent(IEvent myevent)  
        {  
            this._events = myevent;  
              
        }  
}  

如上所示,我使用GetEvents()方法调用College事件,其中事件类型作为抽象类型的参数传递。 这将帮助我在不影响College 的情况下添加或更改事件,换句话说,两者都是分离的。 这就是我可以调用该方法的方法。

College coll = new College();  
coll.GetEvent(new FootballEvent()); 

3、属性注入

  这是最常用的方法,我们通过创建接口类型的属性来注入具体类。

class College  
{  
        private IEvent _events;  
        public IEvent MyEvent  
        {  
            set  
            {  
                _events = value;  
            }  
        }  
}  

如上所示,MyEvent属性的setter将获取一个具体对象并将其绑定到接口。 我的类与具体的对象低耦合。 现在对任何类型的Event类的任何更改都不会影响我的College类。

College coll = new College();  
coll.MyEvent = new FootballEvent(); 

4、服务器定位注入

  服务定位器可以像一个简单的运行时映射器。 这允许在运行时添加代码而无需重新编译应用程序,在某些情况下甚至无需重新启动它。

 public class College
    {
        private IEvent _events = null;
        EventLocator el = new EventLocator();

        public College(int index)
        {
            _events = el.LocateEvent(index);
        }
    }

    public class EventLocator
    {
        public IEvent LocateEvent(int index)
        {
            if (index == 1)
            {
                return  new FootballEvent();
            }
            else if(index == 2)
            {
                 return  new PartyEvent();
            }
            else
            {
                return  new TechEvent();
            }
        }
    }

在上面的代码片段中,您可以看到 Events 和 College 之间有一个EventLocator类,它可以帮助我们在不知道具体类型的情况下找到服务。 我只是在构造函数中传递索引值,而构造函数又调用第三方来定位事件并将其返回给构造函数。 因此,对EventLocator的任何更改都不会影响College类。

College coll = new College(1);  
coll.GetEvents();  

实时上述原则的优点:

1、它有助于类的解耦。
2、由于解耦,代码的可重用性增加。
3、改进了代码可维护性和测试。

五、总结

   控制反转(IOC)讨论了谁将启动调用,其中依赖注入(DI)讨论一个对象如何通过抽象获取对其他对象的依赖。

 

这边文章主要引用国外网友的文章,若有觉得有不合理之处,可以查看原文 :https://www.c-sharpcorner.com/UploadFile/cda5ba/dependency-injection-di-and-inversion-of-control-ioc/

转载于:https://www.cnblogs.com/pengnanfa/p/10382747.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值