深入浅出控制反转/依赖注入(IoC/DI)(转)

来源:互联网 发布:c语言中的延时函数 编辑:程序博客网 时间:2024/06/07 01:43

这周开始着手Spring,刚开始就被控制反转、依赖注入这两个名词给难住了。

所以在网上找到了一篇比较好的文章来详细的解释了依赖注入的由来和过程。虽然是文章里的代码都是c#写的,但是代码的大致意思还是清楚的。特别是开始的那个游戏开发的例子比较经典,看了之后理解后面的部分会很容易!

附上链接:依赖注入那些事儿-T2噬菌体。


以下算是我的学习小结吧。

Tip:OCP原则,即开放关闭原则,指设计应该对拓展开放,对修改关闭。

Tip:策略模式,英文名Strategy Pattern,指定义算法族,分别封装起来,让他们之间可以相互替换,此模式使得算法的变化独立于客户。

Tip:UML类图,描述系统中各个模块之间的关系,包括类或类与接口的继承关系,类之间的依赖、聚合等关系。它还描述每一个类的详细信息,包括变量和方法。


依赖注入的由来

随着面向对象分析与设计的发展,一个良好的设计,核心原则之一就是将变化隔离,使得变化部分发生变化时,不变部分不受影响(这也是OCP的目的)。为了做到这一点,要利用面向对象中的多态性,使用多态性后,客户类不再直接依赖服务类,而是依赖于一个抽象的接口,这样,客户类就不能在内部直接实例化具体的服务类。但是,客户类在运作中又客观需要具体的服务类提供服务,因为接口是不能实例化去提供服务的。就产生了“客户类不准实例化具体服务类”和“客户类需要具体服务类”这样一对矛盾。为了解决这个矛盾,开发人员提出了一种模式:客户类定义一个注入点,用于服务类实现接口的具体类,而客户类的客户类负责根据情况,实例化服务类,注入到客户类中,从而解决了这个矛盾


依赖注入的定义

依赖注入(Dependency Injection),是这样一个过程:由于某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只定义一个注入点。在程序运行过程中,客户类不直接实例化具体服务类实例,而是客户类的运行上下文环境或专门组件(IoC Container)负责实例化服务类,然后将其注入到客户类中,保证客户类的正常运行。


依赖注入的类别

setter注入

Setter注入(Setter Injection)是指在客户类中,设置一个服务类接口类型的数据成员,并设置一个Set方法作为注入点,这个Set法接受一个具体的服务类实例为参数,并将它赋给服务类接口类型的数据成员。 



厚颜无耻的把代码搬过来。。。
服务类接口
using System;using System.Collections.Generic;using System.Linq;using System.Text;  namespace SetterInjection{    internal interface IServiceClass    {        String ServiceInfo();    }}
服务类A
using System;using System.Collections.Generic;using System.Linq;using System.Text;  namespace SetterInjection{    internal class ServiceClassA : IServiceClass    {        public String ServiceInfo()        {            return "我是ServceClassA";        }    }}
服务类B
using System;using System.Collections.Generic;using System.Linq;using System.Text;  namespace SetterInjection{    internal class ServiceClassB : IServiceClass    {        public String ServiceInfo()        {            return "我是ServceClassB";        }    }}
客户类
using System;using System.Collections.Generic;using System.Linq;using System.Text;  namespace SetterInjection{    internal class ClientClass    {        private IServiceClass _serviceImpl;          public void Set_ServiceImpl(IServiceClass serviceImpl)        {            this._serviceImpl = serviceImpl;        }          public void ShowInfo()        {            Console.WriteLine(_serviceImpl.ServiceInfo());        }    }}
测试类
using System;using System.Collections.Generic;using System.Linq;using System.Text;  namespace SetterInjection{    class Program    {        static void Main(string[] args)        {            IServiceClass serviceA = new ServiceClassA();            IServiceClass serviceB = new ServiceClassB();            ClientClass client = new ClientClass();              client.Set_ServiceImpl(serviceA);            client.ShowInfo();            client.Set_ServiceImpl(serviceB);            client.ShowInfo();        }    }}
运行结果:
构造注入
构造注入(Constructor Injection)是指在客户类中,设置一个服务类接口类型的数据成员,并以构造函数为注入点,这个构造函数接受一个具体的服务类实例为参数,并将它赋给服务类接口类型的数据成员。
上图是构造注入的示意图,可以看出,与Setter注入很类似,只是注入点由Setter方法变成了构造方法。这里要注意,由于构造注入只能在实例化客户类时注入一次,所以一点注入,程序运行期间是没法改变一个客户类对象内的服务类实例的。具体实现部分与setter注入相似,唯一不同在于构造函数取代set方法称为注入点。
依赖获取
依赖获取(Dependency Locate)是指在系统中提供一个获取点,客户类仍然依赖服务类的接口。当客户类需要服务类时,从获取点主动取得指定的服务类,具体的服务类类型由获取点的配置决定。
这种方法变被动为主动,使得客户类在需要时主动获取服务类,而将多态性的实现封装到获取点里面。获取点可以有很多种实现,也许最容易想到的就是建立一个Simple Factory作为获取点,客户类传入一个指定字符串,以获取相应服务类实例。如果所依赖的服务类是一系列类,那么依赖获取一般利用Abstract Factory模式构建获取点,然后,将服务类多态性转移到工厂的多态性上,而工厂的类型依赖一个外部配置,如XML文件。
因为涉及到工厂模式(还没学。。),这里就不做总结了(还是把原文的那部分看了的,理解起来也不难)
总之,看了这篇文章后收获还是挺多的。










0 0