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 中的入門使用,方便初學者更上一層樓。加油,共勉!

相關參考

相關文章
相關標籤/搜索