MEF 插件式开发 - 小试牛刀

简介: 原文:MEF 插件式开发 - 小试牛刀目录 MEF 简介 实践出真知面向接口编程 控制反转(IOC) 构建入门级 MEF 相关参考 MEF 简介 Managed Extensibility Framework 即 MEF 是用于创建轻量、可扩展应用程序的库。
原文: MEF 插件式开发 - 小试牛刀

目录


MEF 简介

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

在进行传统的 C/S 端开发,如果项目不是特别复杂,常规的开发模式还是可以应对的。但是一旦场景复杂度提升,一个小小业务功能的修改就需要更新整个客户端,这个对于开发者来说是不能忍受的。因此微软为我们引入了 MEF 的开发模式。允许我们将众多的业务模块拆分开来设计成独立的 DLL,然后由客户端来进行统一加载,这样就能解决上述我们所说的痛点。

实践出真知

创建一个高扩张的 MEF 框架涉及的技术点较多。为了方便初学者能较快理解,上手实践,我这里主要通过 3 个方面来进行相关叙述。

面向接口编程

如果你还不能理解什么是面向接口编程的话,那你应该还不能区分抽象类和接口之间的区别。其实在刚开始的时候我也不是很能理解,直到我看到了一句话:抽象类规定了你是什么,接口规定了你能干什么,只要你能理解这句话,那么你应该就明白什么是面向接口编程,这种编程方式的好处是统一化了业务的暴露方式,方便外部使用。下面我们看一个简单的例子。

public interface IMessage
{
    void Send();
}

public class EmailService : IMessage
{
    public void Send()
    {
        Console.WriteLine("Email Send Message");
    }
}

public class SMSService : IMessage
{
    public void Send()
    {
        Console.WriteLine("SMS Send Message");
    }
}

class Program
{
    static void Main(string[] args)
    {
        IMessage email = new EmailService();
        email.Send();

        IMessage sms = new SMSService();
        sms.Send();

        Console.ReadKey();
    }
}

上述代码中,我们创建了一个 IPlugin 的接口,接口定义了一个 ShowPluginName() 方法,然后我们再定义了两个独立的类来分别继承该接口并实现相应的接口函数。在主函数中,我们只需要定义一个接口类型的对象,然后接收一个具体的类型实例,函数就会输出对应的正确信息。这样编程的好处就不言而喻了。代码很简单,这里就不过多描述。输出结果如下图所示

img_85f214bcf897b0e4fbea70910efac44d.png

控制反转(IOC)

所谓控制反转,就是将对象初始化的控制权交出去。要实现控制反转,我们需要有面向接口编程的接口,同样的,这里也是展示一个代码段来叙述。

public interface IMessage
{
    void Send();
}

public class EmailService : IMessage
{
    public void Send()
    {
        Console.WriteLine("Email Send Message");
    }
}

public class SMSService : IMessage
{
    public void Send()
    {
        Console.WriteLine("SMS Send Message");
    }
}

public static class Factory
{
    public static EmailService GetEmailService() => new EmailService();

    public static SMSService GetSMSService() => new SMSService();
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("DependencyService:");
        DependencyService();

        Console.WriteLine();

        Console.WriteLine("InversionDependencyService:");
        InversionDependencyService();

        Console.ReadKey();
    }

    static void DependencyService()
    {
        EmailService fooEmailService = new EmailService();
        fooEmailService.Send();
    }
    static void InversionDependencyService()
    {
        IMessage fooMessage = Factory.GetEmailService();
        fooMessage.Send();
        fooMessage = Factory.GetSMSService();
        fooMessage.Send();
    }
}

在这个例子中,我们通过工厂模式创建具体的服务,然后供主程序来调用,代码依然很简单,分别用传统创建服务的方式和 控制反转的方式来进行对比。程序输出如下

img_e8d592dbb8237894f7c21b837f08fbca.png

构建入门级 MEF

有了上面两个知识点做铺垫,我们可以开始创建一个入门级的 MEF 示例程序。想要在程序中使用 MEF 的话需要引入如下程序集

  • System.ComponentModel.Composition

这里还是以控制台程序来展示。项目结构如下图所示

img_57cff2895a62d657e0d20a6c64a7ca91.png
  • MefSample.Core:核心接口定义在该项目中
  • MefSample.EmailService:插件,需要引用 MefSample.Core 和 System.ComponentModel.Composition
  • MefSample.SMSService:插件,需要引用 MefSample.Core 和 System.ComponentModel.Composition
  • MefSample:主程序,需要引用 MefSample.Core 和 System.ComponentModel.Composition

注意:上述所有项目程序的输出目录需要保持一致

MefSample.Core 代码段

public interface IMessage
{
    void Send();
}

MefSample.EmailService 代码段

[Export(typeof(IMessage))]
public class EmailService: IMessage
{
    public void Send()
    {
        Console.WriteLine("Email Send Message");
    }
}

MefSample.SMSService 代码段

[Export(typeof(IMessage))]
public class SMSService : IMessage
{
    public void Send()
    {
        Console.WriteLine("SMS Send Message");
    }
}

MefSample 代码段

class Program
{
    static void Main(string[] args)
    {
        var dir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
        var catalog = new DirectoryCatalog(dir.FullName, "*.dll");
        using (CompositionContainer container = new CompositionContainer(catalog))
        {
            IEnumerable<IMessage> messages = container.GetExportedValues<IMessage>();
            if (messages != null)
            {
                foreach (var message in messages)
                {
                    message.Send();
                }
            }
        }
        Console.ReadKey();
    }
}

仔细观察的话,其实上述代码还是挺简单的, 我这里使用了 DirectoryCatalog 的方式来寻找目标插件,感兴趣的朋友可以试试其他方式:AggregateCatalogAssemblyCatalogDirectoryCatalog。当然,你也可以自定义。程序输出结果如下图所示

img_7712d4cb0b1a42e3aa544aa8dacc892e.png

好了,程序写到这里相信你对 MEF 也多少有些了解。我没有过多的讲解抽象理论,而是更多地通过代码来描述我所想要说的。在下篇文章中,我将会简单讲述一下 MEF 在 WPF 中的入门使用,方便初学者更上一层楼。加油,共勉!

相关参考

目录
相关文章
|
开发框架 小程序 JavaScript
基于mpvue框架的小程序项目搭建入门教程一
基于mpvue框架的小程序项目搭建入门教程一
157 0
|
4月前
|
负载均衡 数据可视化 NoSQL
强烈推荐,好用的时序图开源插件PlantUML!
PlantUML这个开源时序图插件,它通过简单的语法和自动化的图形线条关联解决了传统画图软件中对齐困难、逻辑判断不易表示等问题,并提供了美观的图形和易于修改的特点,特别适合新入职场的开发者快速上手绘制高质量的时序图。
强烈推荐,好用的时序图开源插件PlantUML!
|
5月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue的编程语言在线学习平台的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue的编程语言在线学习平台的详细设计和实现(源码+lw+部署文档+讲解等)
48 1
|
5月前
|
JavaScript
小而美的IKUN-UI组件库源码学习(前言)
小而美的IKUN-UI组件库源码学习(前言)
136 0
小而美的IKUN-UI组件库源码学习(前言)
|
人工智能 Go
神级插件Bito介绍及使用
神级插件Bito介绍及使用
|
设计模式 Java API
Android组件化开发(七)--从零开始教你分析项目需求并实现
前面几篇文章我们封装了几个组件化功能组件:包括:**网络请求组件,图片加载请求组件,应用保活组件,音乐播放组件封装。** &gt; 每个组件都可以直接拿到自己项目中使用,当然还需根据自己项目要求进行优化。
Android组件化开发(七)--从零开始教你分析项目需求并实现
个人若依框架学习大杂烩
个人若依框架学习大杂烩
160 0
|
JavaScript 前端开发
成为构架师必知的Vue目录结构和构建规范,恩师王红元的蘑菇街项目❤
成为构架师必知的Vue目录结构和构建规范,恩师王红元的蘑菇街项目❤
182 0
|
监控 Java Spring
平台化三部曲之二模块化开发 - Google Guice 平台模块化开发的果汁
该文章来自阿里巴巴技术协会(ATA)精选集 在前文《从Eclipse平台看交易平台化》中,主要探讨平台的扩展机制。 本文将继续探讨平台化开发中另一个重要方面: 模块机制。在阿里系统开发中,大家都有自己的模块化开发方式。比如目前交易中的TMF框架(Trade Module Framwork)
12154 2
|
C# 容器 开发框架
MEF 插件式开发 - WPF 初体验
原文:MEF 插件式开发 - WPF 初体验 目录 MEF 在 WPF 中的简单应用 加载插件 获取元数据 依赖注入 总结 MEF 在 WPF 中的简单应用 MEF 的开发模式主要适用于插件化的业务场景中,C/S 和 B/S 中都有相应的使用场景,其中包括但不限于 ASP.NET MVC 、ASP WebForms、WPF、UWP 等开发框架。
1176 0