首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

可插拔式應用程式架構設計實戰:從核心主機到插件版本相容策略

     編輯:關於.NET

核心概念:三大支柱

參考 Windows/MSN 架構,可插拔系統包含:

  1. 主應用程式:提供運行環境、核心功能(如郵件通知)。
  2. 公用介面:定義主機與插件的契約(IPluginHost、IPlugin)。
  3. 插件:實作 IPlugin,由主程式動態載入(DLL)。

介面定義

// 主機介面:插件可呼叫 AddMenuItem、RegisterComponent
public interface IPluginHost
{
    void AddMenuItem(string name, MenuItemClickedHandler clickHandler);
    void RegisterComponent<T>(T component) where T : class;
    void MailNotice(string message);
}
public delegate void MenuItemClickedHandler(string name);

// 插件介面:主程式呼叫 Initialize、DoSomething
public interface IPlugin
{
    void Initialize(IPluginHost pluginHost);
    void DoSomething();
}

主程式載入插件(反射)

private List<IPlugin> pluginList = new List<IPlugin>();

public void LoadPlugin()
{
    string pluginDir = Path.Combine(Directory.GetCurrentDirectory(), "Plugins");
    foreach (string fileName in Directory.GetFiles(pluginDir, "*.dll"))
    {
        Assembly asm = Assembly.LoadFile(fileName);
        foreach (Type t in asm.GetTypes())
        {
            if (!t.IsPublic || t.IsAbstract || t.IsInterface) continue;
            Type pluginInterface = t.GetInterface(typeof(IPlugin).FullName);
            if (pluginInterface != null)
            {
                IPlugin plugin = (IPlugin)Activator.CreateInstance(t);
                plugin.Initialize(this); // 傳入主機介面
                pluginList.Add(plugin);
                break; // 假設每個 DLL 只有一個插件
            }
        }
    }
}

主程式啟動流程

void Start()
{
    MailNotice("中秋快樂"); // 核心功能
    LoadPlugin();            // 載入擴充功能
    if (pluginList.Count > 0)
    {
        foreach (var p in pluginList) p.DoSomething();
    }
    Console.ReadLine();
}

插件實作範例

PluginA:手機簡訊通知

public class PluginA : IPlugin
{
    public void Initialize(IPluginHost host)
    {
        host.AddMenuItem("Click me", OnClick);
    }
    private void OnClick(string name) => Console.WriteLine("Omg! You clicked me!");
    public void DoSomething() => Console.WriteLine("手機簡訊通知:中秋快樂");
}

PluginB:MSN 訊息通知

public class PluginB : IPlugin
{
    public void Initialize(IPluginHost host)
    {
        host.AddMenuItem("Click me", OnClick);
    }
    private void OnClick(string name) => Console.WriteLine("Omg! You clicked me!");
    public void DoSomething() => Console.WriteLine("MSN 訊息通知:中秋快樂");
}

版本相容策略:依賴注入新介面

需求:主程式新增 ShowMessageBox 供插件呼叫,但 不可修改已發布的 IPluginHost。

  1. 定義新介面 IMessageBoxHost。
  2. 主程式建構子注入 IMessageBoxHost 實作。
  3. 插件建構子同樣注入。
  4. 載入時透過 Activator.CreateInstance(type, new object[] { msgBoxHost }) 傳遞。
public interface IMessageBoxHost { void ShowMessageBox(string message); }

// 主程式
public Program(IMessageBoxHost mbh) { this.messageBoxHostInstance = mbh; }

// 插件
public PluginA(IMessageBoxHost mbh) { this.messageBoxHost = mbh; }

// 載入時
IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType, new object[] { messageBoxHostInstance });

目錄結構與執行效果

插件目錄結構 主程式執行結果 插件載入後效果

結語

本文示範從零建立可插拔架構:介面契約、反射載入、主機服務暴露、插件生命週期,並以依賴注入解決介面演進的版本相容難題。完整代碼可參考:Plugin.rar。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved