zoukankan      html  css  js  c++  java
  • 依赖注入(转摘)

    依赖注入产生的背景:

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

    依赖注入的正式定义:

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

    依赖注入方法:

    1、Setter注入

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

    示例:

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace Szh.DI.Setter
    {
        internal interface IService
        {
            void ServiceInfo();
        }
        internal class ServiceA : IService
        {
            public void ServiceInfo()
            {
                Console.WriteLine("Here is ServiceA !");
            }
        }
        internal class ServiceB:IService
        {
            public void ServiceInfo()
            {
                Console.WriteLine("Here is ServiceB !");
            }
        }
        internal class ClientClass
        {
            private IService _service;
            // Setter Injection.
            public void Set_Service(IService isrv)
            {
                this._service = isrv;
            }
            // Constructor Injection.
            public ClientClass(IService isrv)
            {
                this._service = isrv;
            }
            public void ShowServiceInfo()
            {
                _service.ServiceInfo();
            }

        }
        class Program
        {
            static void Main(string[] args)
            {
                IService srvA = new ServiceA();
                IService srvB = new ServiceB();

                // Constructor Injection.
                ClientClass client = new ClientClass(srvA);
                client.ShowServiceInfo();

                ClientClass client2 = new ClientClass(srvB);
                client2.ShowServiceInfo();
                //~ Constructor Injection.

    /*          Setter Injection.
                ClientClass client = new ClientClass();


                client.Set_Service(srvA);
                client.ShowServiceInfo();

                client.Set_Service(srvB);
                client.ShowServiceInfo();*/


                Console.Read();
            }
        }
    }

    2、构造注入

    (是通过客户类的构造函数,向客户类注入服务类实例。见上例)

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

    3、依赖获取

    依赖获取(Dependency Locate)是指在系统中提供一个获取点,客户类仍然依赖服务类的接口。当客户类需要服务类时,从获取点主动取得指定的服务类,具体的服务类类型由获取点的配置决定。

    可以看到,这种方法变被动为主动,使得客户类在需要时主动获取服务类,而将多态性的实现封装到获取点里面。获取点可以有很多种实现,也许最容易想到的就是建立一个Simple Factory作为获取点,客户类传入一个指定字符串,以获取相应服务类实例。如果所依赖的服务类是一系列类,那么依赖获取一般利用Abstract Factory模式构建获取点,然后,将服务类多态性转移到工厂的多态性上,而工厂的类型依赖一个外部配置,如XML文件。

    示例(我们假设有个程序,既可以使用Windows风格外观,又可以使用Mac风格外观,而内部业务是一样的。):

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using System.Reflection;

    namespace Szh.DIReflectinon.DepLocate
    {
        internal interface IWindow
        {
            string ShowInfo();
        }
        internal interface IButton
        {
            string ShowInfo();
        }
        internal interface ITextBox
        {
            string ShowInfo();
        }
        public class MacWindow : IWindow
        {
            public string ShowInfo()
            {
                return "Mac 风格窗口!";
            }
        }
        public class MacButton : IButton
        {
            public string ShowInfo()
            {
                return "Mac 风格按钮!";
            }
        }
        public class MacTextBox : ITextBox
        {
            public string ShowInfo()
            {
                return "Mac 风格文本框!";
            }
        }
        public class WinWindow:IWindow
        {
            public string ShowInfo()
            {
                return "Windows 风格窗口!";
            }
        }
        public class WinButton : IButton
        {
            public string ShowInfo()
            {
                return "Windows 风格按钮!";
            }
        }
        public class WinTextBox : ITextBox
        {
            public string ShowInfo()
            {
                return "Windows 风格文本框!";
            }
        }
        public class UbuntuWindow:IWindow
        {
            public string ShowInfo()
            {
                return "Ubuntu 风格窗口!";
            }
        }
        public class UbuntuButton : IButton
        {
            public string ShowInfo()
            {
                return "Ubuntu 风格按钮!";
            }
        }
        public class UbuntuTextBox : ITextBox
        {
            public string ShowInfo()
            {
                return "Ubuntu 风格文本框!";
            }
        }
        static class ReflectionFactory
        {
            static string windowstyle;
            static string buttonstyle;
            static string textboxstyle;

            static ReflectionFactory()
            {
                XmlDocument xmlDoc = new XmlDocument();

                xmlDoc.Load(".\\config.xml");

                XmlNode xmlNode = xmlDoc.ChildNodes[1];

                windowstyle = xmlNode.ChildNodes[0].ChildNodes[0].Value;
                buttonstyle = xmlNode.ChildNodes[1].ChildNodes[0].Value;
                textboxstyle = xmlNode.ChildNodes[2].ChildNodes[0].Value;
            }
            public static IWindow MakeWindow()
            {
                return Assembly.Load("Szh.DIReflectinon.DepLocate").CreateInstance("Szh.DIReflectinon.DepLocate." + windowstyle) as IWindow;
            }
            public static IButton MakeButton()
            {
                return Assembly.Load("Szh.DIReflectinon.DepLocate").CreateInstance("Szh.DIReflectinon.DepLocate." + buttonstyle) as IButton;
            }
            public static ITextBox MakeTextBox()
            {
                return Assembly.Load("Szh.DIReflectinon.DepLocate").CreateInstance("Szh.DIReflectinon.DepLocate." + textboxstyle) as ITextBox;
            }


        }
        class Program
        {
            static void Main(string[] args)
            {
                IWindow window = ReflectionFactory.MakeWindow();
                Console.WriteLine("创建 " + window.ShowInfo());

                IButton button = ReflectionFactory.MakeButton();
                Console.WriteLine("创建 " + button.ShowInfo());

                ITextBox textbox = ReflectionFactory.MakeTextBox();
                Console.WriteLine("创建 " + textbox.ShowInfo());

                Console.Read();
            }
        }
    }

    配置文件config.xml :

    <?xml version="1.0" encoding="utf-8" ?>
    <config>
     <window>UbuntuWindow</window>
     <button>MacButton</button>
     <textBox>MacTextBox</textBox>
    </config>


    使用了反射的好处在于:

    当新增加类型时,只需派生出新的类型类(如UbuntuWindow,UbuntuButton,UbuntuTextBox等 ),

    不需修改已有代码,而只需实现这个类,修改配置文件。

    符合OCP。

     

  • 相关阅读:
    HTTP断点续传 规格严格
    Java Shutdown 规格严格
    linux 命令源码 规格严格
    JTable调整列宽 规格严格
    linux 多CPU 规格严格
    Hello can not find git path 规格严格
    Kill 规格严格
    拜拜牛人 规格严格
    Swing 规格严格
    Debugging hangs in JVM (on AIX but methodology applicable to other platforms) 规格严格
  • 原文地址:https://www.cnblogs.com/MayGarden/p/1653573.html
Copyright © 2011-2022 走看看