• 关于.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

  • 相关阅读:
    ubuntu 系统命令
    js模板引擎实例一
    读取页面上所有的checkbox
    使用fileReader实现图片预览
    html5中的audio标签针对IOS系统的兼容处理
    CSS单位
    使用变换属性的旋转和动画属性实现大风车效果
    css动画属性--轮播图效果
    php curl详解
    linux权限详解
  • 原文地址:https://www.cnblogs.com/dongweian/p/14249040.html
Copyright © 2020-2023  润新知