加入收藏 | 设为首页 | 会员中心 | 我要投稿 安卓应用网 (https://www.0791zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 程序设计 > 正文

依赖注入的那些事儿(下)[转载]

发布时间:2020-05-27 16:31:05 所属栏目:程序设计 来源:互联网
导读:1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: 6: namespace SetterInjection 7: { 8: class Program 9: { 10:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: 
   6: namespace SetterInjection
   7: {
   8:     class Program
   9:     {
  10:         static void Main(string[] args)
  11:         {
  12:             IServiceClass serviceA = new ServiceClassA();
  13:             IServiceClass serviceB = new ServiceClassB();
  14:             ClientClass client = new ClientClass();
  15: 
  16:             client.Set_ServiceImpl(serviceA);
  17:             client.ShowInfo();
  18:             client.Set_ServiceImpl(serviceB);
  19:             client.ShowInfo();
  20:         }
  21:     }
  22: }

运行结果如下:

依赖注入的那些事儿(下)[转载]

图3.2 Setter注入运行结果

3.1.2 构造注入

另外一种依赖注入方式,是通过客户类的构造函数,向客户类注入服务类实例。

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

依赖注入的那些事儿(下)[转载]

图3.3 构造注入示意

图3.3是构造注入的示意图,可以看出,与Setter注入很类似,只是注入点由Setter方法变成了构造方法。这里要注意,由于构造注入只能在实例化客户类时注入一次,所以一点注入,程序运行期间是没法改变一个客户类对象内的服务类实例的。

由于构造注入和Setter注入的IServiceClass,ServiceClassA和ServiceClassB是一样的,所以这里给出另外ClientClass类的示例代码。

Code:ClientClass
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: 
   6: namespace ConstructorInjection
   7: {
   8:     internal class ClientClass
   9:     {
  10:         private IServiceClass _serviceImpl;
  11: 
  12:         public ClientClass(IServiceClass serviceImpl)
  13:         {
  14:             this._serviceImpl = serviceImpl;
  15:         }
  16: 
  17:         public void ShowInfo()
  18:         {
  19:             Console.WriteLine(_serviceImpl.ServiceInfo());
  20:         }
  21:     }
  22: }

可以看到,唯一的变化就是构造函数取代了Set_ServiceImpl方法,成为了注入点。

3.1.3 依赖获取

上面提到的注入方式,都是客户类被动接受所依赖的服务类,这也符合“注入”这个词。不过还有一种方法,可以和依赖注入达到相同的目的,就是依赖获取。

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

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

不过,不论使用Simple Factory还是Abstract Factory,都避免不了判断服务类类型或工厂类型,这样系统中总要有一个地方存在不符合OCP的if…else或switch…case结构,这种缺陷是Simple Factory和Abstract Factory以及依赖获取本身无法消除的,而在某些支持反射的语言中(如C#),通过将反射机制的引入彻底解决了这个问题(后面讨论)。

下面给一个具体的例子,现在我们假设有个程序,既可以使用Windows风格外观,又可以使用Mac风格外观,而内部业务是一样的。

依赖注入的那些事儿(下)[转载]

图3.4 依赖获取示意

上图乍看有点复杂,不过如果读者熟悉Abstract Factory模式,应该能很容易看懂,这就是Abstract Factory在实际中的一个应用。这里的Factory Container作为获取点,是一个静态类,它的“Type构造函数”依据外部的XML配置文件,决定实例化哪个工厂。下面还是来看示例代码。由于不同组件的代码是相似的,这里只给出Button组件的示例代码,完整代码请参考文末附上的完整源程序。

Code:按钮接口
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: 
   6: namespace DependencyLocate
   7: {
   8:     internal interface IButton
   9:     {
  10:         String ShowInfo();
  11:     }
  12: }
Code:Windows风格按钮
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: 
   6: namespace DependencyLocate
   7: {
   8:     internal sealed class WindowsButton : IButton
   9:     {
  10:         public String Description { get; private set; }
  11: 
  12:         public WindowsButton()
  13:         {
  14:             this.Description = "Windows风格按钮";
  15:         }
  16: 
  17:         public String ShowInfo()
  18:         {
  19:             return this.Description;
  20:         }
  21:     }
  22: }
Code:Mac风格按钮
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: 
   6: namespace DependencyLocate
   7: {
   8:     internal sealed class MacButton : IButton
   9:     {
  10:         public String Description { get; private set; }
  11: 
  12:         public MacButton()
  13:         {
  14:             this.Description = " Mac风格按钮";
  15:         }
  16: 
  17:         public String ShowInfo()
  18:         {
  19:             return this.Description;
  20:         }
  21:     }
  22: }
Code:工厂接口
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: 
   6: namespace DependencyLocate
   7: {
   8:     internal interface IFactory
   9:     {
  10:         IWindow MakeWindow();
  11: 
  12:         IButton MakeButton();
  13: 
  14:         ITextBox MakeTextBox();
  15:     }
  16: }
Code:Windows组件工厂
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: 
   6: namespace DependencyLocate
   7: {
   8:     internal sealed class WindowsFactory : IFactory
   9:     {
  10:         public IWindow MakeWindow()
  11:         {
  12:             return new WindowsWindow();
  13:         }
  14: 
  15:         public IButton MakeButton()
  16:         {
  17:             return new WindowsButton();
  18:         }
  19: 
  20:         public ITextBox MakeTextBox()
  21:         {
  22:             return new WindowsTextBox();
  23:         }
  24:     }
  25: }
Code:Mac组件工厂
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: 
   6: namespace DependencyLocate
   7: {
   8:     internal sealed class MacFactory : IFactory
   9:     {
  10:         public IWindow MakeWindow()
  11:         {
  12:             return new MacWindow();
  13:         }
  14: 
  15:         public IButton MakeButton()
  16:         {
  17:             return new MacButton();
  18:         }
  19: 
  20:         public ITextBox MakeTextBox()
  21:         {
  22:             return new MacTextBox();
  23:         }
  24:     }
  25: }
Code:获取点
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.Xml;
   6: 
   7: namespace DependencyLocate
   8: {
   9:     internal static class FactoryContainer
  10:     {
  11:         public static IFactory factory { get; private set; }
  12: 
  13:         static FactoryContainer()
  14:         {
  15:             XmlDocument xmlDoc = new XmlDocument();
  16:             xmlDoc.Load("http://www.cnblogs.com/Config.xml");
  17:             XmlNode xmlNode = xmlDoc.ChildNodes[1].ChildNodes[0].ChildNodes[0];
  18: 
  19:             if ("Windows" == xmlNode.Value)
  20:             {
  21:                 factory = new WindowsFactory();
  22:             }
  23:             else if ("Mac" == xmlNode.Value)
  24:             {
  25:                 factory = new MacFactory();
  26:             }
  27:             else
  28:             {
  29:                 throw new Exception("Factory Init Error");
  30:             }
  31:         }
  32:     }
  33: }
Code:测试代码
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: 
   6: namespace DependencyLocate
   7: {
   8:     class Program
   9:     {
  10:         static void Main(string[] args)
  11:         {
  12:             IFactory factory = FactoryContainer.factory;
  13:             IWindow window = factory.MakeWindow();
  14:             Console.WriteLine("创建 " + window.ShowInfo());
  15:             IButton button = factory.MakeButton();
  16:             Console.WriteLine("创建 " + button.ShowInfo());
  17:             ITextBox textBox = factory.MakeTextBox();
  18:             Console.WriteLine("创建 " + textBox.ShowInfo());
  19: 
  20:             Console.ReadLine();
  21:         }
  22:     }
  23: }

(编辑:安卓应用网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读