zoukankan      html  css  js  c++  java
  • 关于.NET中的控制反转(二)- 依赖注入之 MEF

    一、MEF是什么

    ​ Managed Extensibility Framework (MEF) 是用于创建可扩展的轻量级应用程序的库。 它让应用程序开发人员得以发现和使用扩展且无需配置。 它还让扩展开发人员得以轻松地封装代码并避免脆弱的紧密依赖性。 MEF 让扩展不仅可在应用程序内重复使用,还可以跨程序重复使用。

    MEF 通过组合提供了一种隐式发现它们的方法,而不是明确记录可用组件。 MEF 组件(称为一个部件),以声明方式详细说明了其依赖项(称为导入)及其可提供的功能(称为导出)。 当创建一个部分时,MEF 组合引擎利用从其他部分获得的功能满足其导入需要。

    一句话,MEF就是面向接口编程的应用,接口定义行为,它把实例化类放到代码运行的时候,通过容器参数确定。

    二、MEF示例

    ​ 在我们国家,不管你在哪个银行办理银行卡,只要银行卡有银联标识,那么你就基本可以在任意一家银行取钱、存钱。中国银联(China UnionPay)成立于2002年3月,是经国务院同意,中国人民银行批准设立的中国银行卡联合组织,在境内的银行必须都支持银联。也就是说,中国银联定义了一些行为,例如用户可以取钱、存钱,任意一家境内银行都必须支持银联定义的行为。因此,你在任意一家银行办理银行卡后,就可以在所有的银行都进行取钱、存钱等及行为。下面我们以此为例,进行一个简单的例子:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.ComponentModel.Composition;
      4 using System.ComponentModel.Composition.Hosting;
      5 using System.Linq;
      6 using System.Reflection;
      7 using System.Text;
      8 using System.Threading.Tasks;
      9 
     10 namespace MEF1
     11 {
     12     class Operation
     13     {
     14         static void Main(string[] args)
     15         {
     16             BlankOperation("CBC",300,100);
     17             Console.WriteLine("------------------------------");
     18             BlankOperation("BOC",888,666);
     19             Console.ReadKey();
     20         }
     21 
     22         static void BlankOperation(string bankName,int saveMonenyAmout,int withdrawMoneyAmount)
     23         {
     24             var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
     25             CompositionContainer container = new CompositionContainer(catalog);
     26             var dev = container.GetExportedValue<IUnionPay>(bankName);
     27             dev.SaveMoneny(saveMonenyAmout);
     28             dev.WithdrawMoney(withdrawMoneyAmount);
     29         }
     30     }
     31 
     32   
     33     interface IUnionPay
     34     {
     35         /// <summary>
     36         /// 存钱
     37         /// </summary>
     38         /// <param name="amount">存钱金额</param>
     39         void SaveMoneny(int amount);
     40 
     41         /// <summary>
     42         /// 取钱
     43         /// </summary>
     44         /// <param name="amount">取钱金额</param>
     45         void WithdrawMoney(int amount);
     46 
     47     }
     48 
     49     /// <summary>
     50     /// 工商银行
     51     /// </summary>
     52     [Export("CBC",typeof(IUnionPay))]
     53     class ICBC : IUnionPay
     54     {
     55         public void SaveMoneny(int amount)
     56         {
     57             Console.WriteLine($"把钱存入工商银行,金额为:{amount}");
     58         }
     59 
     60         public void WithdrawMoney(int amount)
     61         {
     62             Console.WriteLine($"从工商银行取钱,金额为:{amount}");
     63         }
     64     }
     65 
     66     /// <summary>
     67     /// 建设银行
     68     /// </summary>
     69     [Export("CCB", typeof(IUnionPay))]
     70     class CCB : IUnionPay
     71     {
     72         public void SaveMoneny(int amount)
     73         {
     74             Console.WriteLine($"把钱存入建设银行,金额为:{amount}");
     75         }
     76 
     77         public void WithdrawMoney(int amount)
     78         {
     79             Console.WriteLine($"从建设银行取钱,金额为:{amount}");
     80         }
     81     }
     82 
     83     /// <summary>
     84     /// 农业银行
     85     /// </summary>
     86     [Export("ABC", typeof(IUnionPay))]
     87     class ABC : IUnionPay
     88     {
     89         public void SaveMoneny(int amount)
     90         {
     91             Console.WriteLine($"把钱存入农业银行,金额为:{amount}");
     92         }
     93 
     94         public void WithdrawMoney(int amount)
     95         {
     96             Console.WriteLine($"从农业银行取钱,金额为:{amount}");
     97         }
     98     }
     99 
    100     /// <summary>
    101     /// 中国银行
    102     /// </summary>
    103     [Export("BOC", typeof(IUnionPay))]
    104     class BOC : IUnionPay
    105     {
    106         public void SaveMoneny(int amount)
    107         {
    108             Console.WriteLine($"把钱存入中国银行,金额为:{amount}");
    109         }
    110 
    111         public void WithdrawMoney(int amount)
    112         {
    113             Console.WriteLine($"从中国银行取钱,金额为:{amount}");
    114         }
    115     }
    116 }
    

    代码运行后,效果如下:

    img

    三、MEF示例改进

    那如果我们再增加一个银行实现类,例如招商银行,那么需要在MEF1解决方案中增加一个 “CMB”类。但如果我们的程序已经运行了,此时关闭程序,就会影响用户在四大行也无法进行取钱和存钱了,那如何在不关闭程序的前提下,还完成招商银行接入银联卡呢?

    答案是为每个银行实现类创建一个解决方案,然后编译成dll文件,这样我们在支持招商银行接入银联时,只需要把 “CMB.dll”文件放入对应目录,就可以即不关闭主程序,还可以无缝支持招商银行接入银联,方案目录如下:

    img

    我们把实现银联的银行的解决方案的生成目录保存在目录 “..inDebugank”,用于测试的解决方案和银联接口的解决方案生成目录保存在目录 “..inDebug”,编译程序,生成文件如下图:

    img

    然后测试解决方案Ioc容器加载的目录也需修改为bank目录下:

     1 using ChinaUnionPay;
     2 using System;
     3 using System.Collections.Generic;
     4 using System.ComponentModel.Composition.Hosting;
     5 using System.IO;
     6 using System.Linq;
     7 using System.Reflection;
     8 using System.Text;
     9 using System.Threading.Tasks;
    10 
    11 namespace BankOperation
    12 {
    13     class Program
    14     {
    15         static void Main(string[] args)
    16         {
    17             while (true)
    18             {
    19                 Console.Write($"请输入银行名称:");
    20                 string name = Console.ReadLine();
    21                 BlankOperation(name, 300, 100);
    22                 Console.WriteLine("----------------------------------");
    23             }
    24         }
    25 
    26         static void BlankOperation(string bankName, int saveMonenyAmout, int withdrawMoneyAmount)
    27         {
    28             AggregateCatalog catelog = new AggregateCatalog();
    29 
    30             // 添加部件所在文件目录
    31             string path = $"{Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath)}\bank\";
    32             catelog.Catalogs.Add(new DirectoryCatalog(path));
    33 
    34             // 声明容器
    35             CompositionContainer container = new CompositionContainer(catelog);
    36             var dev = container.GetExportedValue<IUnionPay>(bankName);
    37 
    38             // 动作调用
    39             dev.SaveMoneny(saveMonenyAmout);
    40             dev.WithdrawMoney(withdrawMoneyAmount);
    41         }
    42     }
    43 }
    

    此时运行测试程序,运行效果如下:

    img

    此时,若在程序运行的时候添加招商银行,我们需添加招商银行的解决方案如下,然后编译生成:

     1 using ChinaUnionPay;
     2 using System;
     3 using System.Collections.Generic;
     4 using System.ComponentModel.Composition;
     5 using System.Linq;
     6 using System.Text;
     7 using System.Threading.Tasks;
     8 
     9 namespace CMB
    10 {
    11     /// <summary>
    12     /// 招商银行
    13     /// </summary>
    14     [Export("CMB",typeof(IUnionPay))]
    15     public class Operation : IUnionPay
    16     {
    17         public void SaveMoneny(int amount)
    18         {
    19             Console.WriteLine($"把钱存入招商银行,金额为:{amount}");
    20         }
    21 
    22         public void WithdrawMoney(int amount)
    23         {
    24             Console.WriteLine($"从招商银行取钱,金额为:{amount}");
    25         }
    26     }
    27 }
    

    运行效果如下:

    img

    我们发现,使用MEF模式可以“高内聚,低耦合”,大大降低了代码的耦合,每增加一个银行接入银联的时候,完全不影响其他银行的正常业务操作。

    四、示例代码地址

    代码地址:https://github.com/Dwayne112401/MEFDemo.git

    控制反转(一)地址:https://www.cnblogs.com/dongweian/p/12511272.html

    控制反转(三)地址:https://www.cnblogs.com/dongweian/p/14267998.html

  • 相关阅读:
    一个好的时间函数
    Codeforces 785E. Anton and Permutation
    Codeforces 785 D. Anton and School
    Codeforces 510 E. Fox And Dinner
    Codeforces 242 E. XOR on Segment
    Codeforces 629 E. Famil Door and Roads
    Codeforces 600E. Lomsat gelral(Dsu on tree学习)
    Codeforces 438D The Child and Sequence
    Codeforces 729E Subordinates
    【ATcoder】D
  • 原文地址:https://www.cnblogs.com/dongweian/p/14249040.html
Copyright © 2011-2022 走看看