程序中经常用到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/ 

posted on 2018-09-16 17:29  爬山虎hu  阅读(268)  评论(0编辑  收藏  举报