MEF 插件式开发之 小试牛刀

MEF 简介

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

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

实践出真知

建立一个高扩张的 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() 方法,而后咱们再定义了两个独立的类来分别继承该接口并实现相应的接口函数。在主函数中,咱们只须要定义一个接口类型的对象,而后接收一个具体的类型实例,函数就会输出对应的正确信息。这样编程的好处就不言而喻了。代码很简单,这里就不过多描述。输出结果以下图所示函数

控制反转(IOC)

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

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();
    }
}

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

构建入门级 MEF

有了上面两个知识点作铺垫,咱们能够开始建立一个入门级的 MEF 示例程序。想要在程序中使用 MEF 的话须要引入以下程序集设计

  • System.ComponentModel.Composition

这里仍是以控制台程序来展现。项目结构以下图所示3d

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

注意:上述全部项目程序的输出目录须要保持一致code

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。固然,你也能够自定义。程序输出结果以下图所示

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

相关参考

相关文章
相关标签/搜索