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。

     

  • 相关阅读:
    ubuntu 读取群晖 nas 盘
    nginx 下载 apk、ipa 不改名zip 设置
    centos 更新时间
    go 交叉编译跨平台
    ffmpeg安装
    批量打开文件夹下所有的指定文件(批处理)
    端口流量统计
    关于 bind 和 dns
    关于使用 certbot 给网站增加 ssl
    Macos下制作可启动的u盘(转)
  • 原文地址:https://www.cnblogs.com/MayGarden/p/1653573.html
Copyright © 2011-2022 走看看