分享

小话设计模式原则之(1):依赖倒置原则DIP(下)

 weijianian 2016-08-07


来源:懒得安分

链接:http://www.cnblogs.com/landeanfen/p/5169163.html


三、使用Unity实现依赖倒置


上面说了那么多,都是在讲依赖倒置的好处,那么在我们的项目中究竟如何具体实现和使用呢?


在介绍依赖倒置具体如何使用之前,我们需要引入IOC容器相关的概念,我们先来看看它们之间的关系。


依赖倒置原则(DIP):一种软件架构设计的原则(抽象概念)。


控制反转(IoC):一种反转流、依赖和接口的方式(DIP的具体实现方式)。这是一个有点不太好理解和解释的概念,通俗地说,就是应用程序本身不负责依赖对象的创建和维护,而是将它交给一个外部容器(比如Unity)来负责,这样控制权就由应用程序转移到了外部IoC 容器,即控制权实现了所谓的反转。例如在类型A中需要使用类型B的实例,而B 实例的创建并不由A 来负责,而是通过外部容器来创建。


依赖注入(DI):IoC的一种实现方式,用来反转依赖(IoC的具体实现方式)。园子里面很多博文里面说IOC也叫DI,其实根据博主的理解,DI应该是IOC的具体实现方式,比如我们如何实现控制反转,答案就是通过依赖注入去实现。


IoC容器:依赖注入的框架,用来映射依赖,管理对象创建和生存周期(DI框架),自动创建、维护依赖对象。


这些名词是不是有点熟呢?博主之前介绍过MEF,之前使用MEF做过依赖注入,详见MEF实现设计上的“松耦合”(1)。其实严格来讲,MEF不能算一种正式的IOC容器,因为它的主要作用还是用于应用程序扩展,避免生成脆弱的硬依赖项,而不是依赖注入。根据博主的了解以及使用经历,常用的IOC容器有:


  • Spring.NET: http://www./


  • Unity:  http://unity./


  • Autofac:  http://code.google.com/p/autofac/


  • Ninject:  http://www./


当然,还有其他的IOC容器这里就不一一列举。Spring.net是从Java的Spring框架移植过来的,功能之强大我们就不多说了,可是自从它宣布不再更新,博主在使用它的时候就非常慎重了。下面博主还是就Unity这种IOC容器来看看依赖倒置的具体实现。


1、Unity引入


Unity如何引入?我们神奇的Nuget又派上用场了。最新的Unity版本已经到了4.0.1。



安装成功后主要引入了三个dll。



2、Unity常用API


UnityContainer.RegisterType();

 

UnityContainer.RegisterType();

 

UnityContainer.RegisterType('keyName');

 

IEnumerable databases = UnityContainer.ResolveAll();

 

IT instance = UnityContainer.Resolve();

 

T instance = UnityContainer.Resolve('keyName');

 

UnitContainer.RegisterInstance('keyName',new T());

 

UnityContainer.BuildUp(existingInstance);

 

IUnityContainer childContainer1 = parentContainer.CreateChildContainer();


3.1、默认注册方式


仍然以上面的场景为例说明,我们注入DeviceMML这个实现类。


class Program

{

    private static IUnityContainer container = null;

    static void Main(string[] args)

    {

        RegisterContainer();

        var oSpider = container.Resolve();

        oSpider.Login();

        var bRes = oSpider.Spider();

 

        Console.ReadKey();

    }

 

    /// 

    /// 代码注入

    /// 

    public static void RegisterContainer()

    {

        container = new UnityContainer();

        container.RegisterType();  

//默认注册方式,如果后面再次默认注册会覆盖前面的

    }

}


运行结果



3.2、带命名方式的注册


上面默认注入的方式中,我们只能注入一种具体的实例,如果我们需要同时注入多个类型的实例呢?看看我们的 RegisterType() 方法有多个重载。


class Program

 {

     private static IUnityContainer container = null;

     static void Main(string[] args)

     {

         RegisterContainer();

         var oSpider = container.Resolve('TL5');

         oSpider.Login();

         var bRes = oSpider.Spider();

 

         Console.ReadKey();

     }

 

     /// 

     /// 代码注入

     /// 

     public static void RegisterContainer()

     {

         container = new UnityContainer();

        container.RegisterType('MML');  

//默认注册(无命名),如果后面还有默认注册会覆盖前面的

         container.RegisterType('Telnet');  

//命名注册

         container.RegisterType('TL2');  

//命名注册

         container.RegisterType('TL5');  

//命名注册

     }

 }


运行结果



4、配置文件注入方式示例


在App.config或者Web.config里面加入如下配置:


   

   

 

 

    

   

     

        

       

       

       

       

     

   

 


在代码里面注册配置文件:


namespace ESTM.Spider

{

    class Program

    {

        private static IUnityContainer container = null;

        static void Main(string[] args)

        {

            ContainerConfiguration();

            var oSpider = container.Resolve('TL5');

            oSpider.Login();

            var bRes = oSpider.Spider();

 

            Console.ReadKey();

        }

 

        /// 

        /// 配置文件注入

        /// 

        public static void ContainerConfiguration()

        {

            container = new UnityContainer();

            UnityConfigurationSection configuration = (UnityConfigurationSection)ConfigurationManager.GetSection(UnityConfigurationSection.SectionName);

            configuration.Configure(container, 'Spider');

        }

 

    }

}


运行结果:



(1)代码说明


register type='ESTM.Spider.IDevice,ESTM.Spider'  mapTo='ESTM.Spider.DeviceMML,ESTM.Spider' name='MML'>register>


节点里面,type对象抽象,mapTo对象具体实例对象,name对象实例的别名。


(2)在app.config里面可以配置多个 container name=”Spider”> 节点,不同的name配置不同的依赖对象。


(3)配置文件注入的灵活之处在于解耦。为什么这么说呢?试想,如果我们的IDevice接口对应着一个接口层,而DeviceMML、DeviceTELNET、DeviceTL2、DeviceTL5等实现类在另外一个实现层里面,我们的UI层(这里对应控制台程序这一层)只需要添加IDevice接口层的引用,不必添加实现层的引用,通过配置文件注入,在运行的时候动态将实现类注入到UI层里面来。这样UI层就对实现层实现了解耦,实现层里面的具体逻辑变化时,UI层里面不必做任何更改。


四、总结


到此,依赖倒置原则的讲解基本结束了。根据博主的理解,设计模式的这些原则是设计模式的理论指导,而设计模式则是这些理论的具体运用。说一千道一万,要想搞懂设计模式,必须先了解设计模式遵循的原则,无论是哪种设计模式都会遵循一种或者多种原则。当然文章可能有理解不当的地方,欢迎大牛们指出


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多