• C# IoC(nversion of Control)、DI(Dependency Injection)


    程序中经常用到IoC(控制反转)和DI(依赖注入),但对其概念的认识也是模模糊糊,今天就详细的了解下

    • 什么是IOC(Inversion of Control )
    • 什么是DI(Dependency Injection )
    • 实现依赖注入的方式
    • IOC、DI的优点

    IOC控制反转

    回想下我们在大学里,有时候需要去参加一些组织活动或者是无聊的讲座。就把College当成类,活动或讲座看成Event。让我们试着把College和Event与IOC联系起来

     

    假设我们有两个类,College和TechEvents,如上图代码,你会发现一些问题:

    1. 这两个类彼此紧密耦合。我们不能有一个没有TecheEvents的College,因为TecheEvents对象是在College构造函数中创建的
    2. 如果我修改了TechEvents,我也需要编译或修改College类
    3. College控制Event的产生。College现在是一个单一事件(社团活动)的组织,如果有其他事件(如FootballEvent、PartyEvent)发生,那就需要修改College,因为College是直接引用的Events

    现在我们需要解决这个问题,否则在College里,不能有其他的Event

    解决这个问题的办法是把事件组织的控制转移到其他地方,就是我们常说的IOC(控制反转)。把控制权反转给其他实体,而不是直接在College中。

    IOC的原理是什么呢?

    Don't Call Me, we will call you

    换言之,Main类不应该有聚合类的具体实现,而应该依赖于该类的抽象。College类应该依赖于TechEvents类的抽象(接口或者抽象类)

        //1.创建用来实现抽象的接口
        interface IEvent { void LoadEventDetail();  }
        //2.所有的Event类应实现IEvent接口
        class TechEvents : IEvent
        {
            public void LoadEventDetail()
            {
                Console.WriteLine("Technology Event Details");
            }
        }
        class FootballEvent:IEvent
        {
            public void LoadEventDetail()
            {
                Console.WriteLine("Football Event Details");
            }
        }
        class PartyEvent:IEvent
        {
            public void LoadEventDetail()
            {
                Console.WriteLine("Party Event Details");
            }
        }
        //3.College构造函数说:I will call the Event
        class College
        {
            private IEvent _events = null;
            public College(IEvent ie)
            {
                this._events = ie;
            }
            public void GetEvents()
            {
                this._events.LoadEventDetail();
            }
        }

    DI依赖注入

    IOC通过DI完成。它解释如何将具体实现注入到使用了抽象类或接口的类中。依赖注入的主要思想是减少类之间的耦合,并将抽象和具体实现的绑定从依赖类中移除。简单来说,DI是一个对象如何知道被抽象的其他对象

    实现依赖注入的方法主要有4种。

    1. 构造器注入

     上面已经讨论了这种方法,具体类的对象被传递给依赖类的构造函数。

    class College
        {
            private IEvent _events = null;
            public College(IEvent ie)
            {
                this._events = ie;
            }
            public void GetEvents()
            {
                this._events.LoadEventDetail();
            }
        }

    事件对象由构造器注入,使其松散耦合。College类将完成它的工作,如果它想获取事件的相关细节,它将基于他想调用的事件,在构造函数中调用它。

    等同于

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

    除了这个优点,另一个优点是当Event发生改变或增加事件,College不需要关心这些。

    2. 属性注入

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

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

    MyEvent属性的setter将具体对象绑定到接口。类与具体对象松散耦合。现在,Event类任何对象的变化都不会影响到College类。

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

    3. 方法注入

    这个方法中,具体的类对象通过方法参数传递给依赖类。

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

    如上所示,通过GetEvent方法调用College事件,其中事件的类型作为抽象类型的参数传递。

                College col1 = new College();
                col1.GetEvent(new FootballEvent());
                col1.GetEvents();        

    4. 服务定位注入

    service locator就像一个简单的运行时mapper。允许在运行时添加代码,而不必重新编译应用程序,并且在某些情况下不必重新启动。

    class College
        {
            private IEvent _events = null;
            EventLocator el = new EventLocator();
            public College(int index)
            {
                this._events = el.LocateEvent(index);
    
            }
            public void GetEvents()
            {
                this._events.LoadEventDetail();
            }
        }
        class EventLocator
        {
            public IEvent LocateEvent(int index)
            {
                if (index == 1) return new FootballEvent();
                else if (index == 2) return new PartyEvent();
                else return new TechEvents();
            }
        }

    上面的代码中,在Events和College类之间有一个EventLocator类,它帮助我在不知道具体类型的情况下定位服务。通过构造函数中的index值,来调用第三方进行定位,并返回给构造函数。EventLocator类的任何改变都不会影响到College类。

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

    实施这一原则的优点

    • 它有助于类的解耦。
    • 由于解耦,增加了代码的可重用性。
    • 提升了代码的可维护性和测试。

     总结:控制反转(IOC)讨论谁将发起调用,而依赖注入(DI)讨论一个对象如何通过抽象获得对其他对象的依赖。

    参考地址:https://www.c-sharpcorner.com/UploadFile/cda5ba/dependency-injection-di-and-inversion-of-control-ioc/ 

  • 相关阅读:
    自写 jQuery 大幅弹窗广告插件(不喜勿拍)
    反省:一个失败的产品
    javascript变量:全局?还是局部?这个得注意!
    前端工作常常会用到的一些经验技巧(三)
    Jquery伪选择器学习笔记
    前端工作常常会用到的一些经验技巧(二)
    (总结)工作中常用的js自定义函数——日期时间类
    js 数组引用 发现的问题
    一位资深程序员大牛给予Java初学者的学习路线建议(转)
    正则表达式
  • 原文地址:https://www.cnblogs.com/pashanhu/p/9656716.html
Copyright © 2020-2023  润新知