您的位置:首页 > 其它

关于.NET中的控制反转(二)- 依赖注入之 MEF

2021-01-07 22:10 381 查看

一、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             B
56c
lankOperation("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">
103c
存钱金额</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 }

代码运行后,效果如下:

三、MEF示例改进

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

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

      

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

      

  然后测试解决方案LOC容器加载的目录也需修改为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 }

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

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

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 }

运行效果如下:

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

四、示例代码地址

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

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: