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

C# 外掛架構改良:從簡單介面到工廠模式與版本管理的可擴充設計

     編輯:關於C語言

前言

針對早期「C# 外掛架構實戰」的回饋,本文重構設計:引入宿主外掛與擴充外掛區分、連線介面、版本資訊、工廠模式建立實例,並以 UML 靜態結構圖說明類別關係,解決原架構擴充性不足的問題。

架構演進目標

  • 統一團隊產品框架:核心庫 + GUI 庫 + 專用應用三層分離。
  • 外掛分為 Host Plugin (宿主) 與 Extension Plugin (擴充),支援巢狀擴充點。
  • 介面導向設計:IConnectable、IExtendible 定義契約。
  • 版本管理:ExtendibleVersionInfo 支援多版本共存與查詢。
  • 工廠方法模式:延遲建立、可擴充的實例化策略。

核心介面定義

IConnectable - 所有可連線物件的基底契約

public interface IConnectable
{
    /// 連線至宿主應用程式;null 表示本身即為宿主
    ConnectionResult Connect(object application);

    /// 版本資訊
    ExtendibleVersionInfo VersionInfo { get; }

    /// 載入完成初始化
    void OnLoad();

    /// 執行主要邏輯
    void Run();

    /// 卸載清理
    void OnDestroy();
}

public enum ConnectionResult { Success, Failed }

public class ExtendibleVersionInfo
{
    private ExtendibleVersionInfo() { } // 單例 Empty 用
    public ExtendibleVersionInfo(string name, string version, string copyright) { ... }
    public ExtendibleVersionInfo(string name, int v1, int v2, int v3, string copyright) { ... }

    public int Major { get; }
    public int Minor { get; }
    public int Build { get; }
    public string Name { get; }
    public string VersionString => $"{Major}.{Minor}.{Build}";
    public string Copyright { get; }

    public static readonly ExtendibleVersionInfo Empty = new ExtendibleVersionInfo();
}

IExtendible - 版本查詢與工廠能力

public interface IExtendible
{
    /// 取得最新版本實例
    IConnectable GetLatestVersion();

    /// 取得指定版本實例
    IConnectable GetSpecifiedVersion(ExtendibleVersionInfo version);

    /// 列舉所有可用版本
    ExtendibleVersionInfo[] EnumerateVersions();
}

UML 靜態結構(文字描述)

+----------------+       +------------------+       +------------------+
|  IConnectable  |<------|  HostPlugin      |       |  ExtensionPlugin |
+----------------+       +------------------+       +------------------+
| Connect(app)   |       | VersionInfo      |       | VersionInfo      |
| VersionInfo    |       | OnLoad/Run/Destroy|      | OnLoad/Run/Destroy|
| OnLoad/Run/    |       | Connect(host)    |       | Connect(host)    |
| OnDestroy      |       +------------------+       +------------------+
+----------------+                ^                        ^
         ^                       |                        |
         |                implements                  implements
         |                       |                        |
+----------------+       +------------------+       +------------------+
|  IExtendible   |<------|  HostFactory     |       |  ExtensionFactory|
+----------------+       +------------------+       +------------------+
| GetLatest()    |       | GetLatestVersion()|      | GetLatestVersion()|
| GetSpecified() |       | EnumerateVersions()|     | EnumerateVersions()|
| Enumerate()    |       +------------------+       +------------------+
+----------------+

簡單工廠 → 工廠方法模式重構

簡單工廠 (原架構缺點)

// 原始:單一工廠類別,新增外掛需修改工廠原始碼 (違反 OCP)
public class PluginFactory
{
    public IConnectable Create(string name)
    {
        return name switch
        {
            "PluginA" => new PluginA(),
            "PluginB" => new PluginB(),
            _ => null
        };
    }
}

工廠方法模式 (改良)

// 抽象工廠
public abstract class PluginFactoryBase : IExtendible
{
    public abstract IConnectable CreateInstance(ExtendibleVersionInfo version);
    public abstract ExtendibleVersionInfo[] EnumerateVersions();

    // IExtendible 實作
    public IConnectable GetLatestVersion() => 
        CreateInstance(EnumerateVersions().OrderByDescending(v => v.Major).ThenByDescending(v => v.Minor).First());

    public IConnectable GetSpecifiedVersion(ExtendibleVersionInfo v) => CreateInstance(v);
}

// 具體工廠 - 每個外掛一個工廠類別,新增外掛只需新增類別
public class PluginAFactory : PluginFactoryBase
{
    public override ExtendibleVersionInfo[] EnumerateVersions() => new[]
    {
        new ExtendibleVersionInfo("PluginA", 1, 0, 0, "Copyright 2024"),
        new ExtendibleVersionInfo("PluginA", 2, 0, 0, "Copyright 2024")
    };

    public override IConnectable CreateInstance(ExtendibleVersionInfo v)
    {
        return v.Major switch
        {
            1 => new PluginA_V1(),
            2 => new PluginA_V2(),
            _ => throw new NotSupportedException($"Unsupported version {v.VersionString}")
        };
    }
}

宿主應用程式載入流程

public class ApplicationHost
{
    private readonly List _factories = new();

    public void RegisterFactory(IExtendible factory) => _factories.Add(factory);

    public IConnectable LoadPlugin(string pluginName, ExtendibleVersionInfo? version = null)
    {
        var factory = _factories.FirstOrDefault(f => 
            f.EnumerateVersions().Any(v => v.Name == pluginName));
        if (factory == null) throw new InvalidOperationException($"Plugin {pluginName} not found");

        IConnectable plugin = version != null 
            ? factory.GetSpecifiedVersion(version) 
            : factory.GetLatestVersion();

        plugin.Connect(this); // 傳入宿主參考
        plugin.OnLoad();
        return plugin;
    }
}

優缺點分析

下一步演進方向

  • 引入 MEF (Managed Extensibility Framework) 或 Autofac 進行組合與相依性注入。
  • 定義 Extension Point / Extension 機制(參考 Eclipse/SharpDevelop),支援 UI 貢獻、命令、服務等多維擴充。
  • 加入 數位簽章驗證 與 AppDomain/AssemblyLoadContext 隔離,提升安全性。
  • 提供 外掛發現掃描器:掃描目錄組件、讀取屬性、自動註冊工廠。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
優點缺點/待改進
符合開放封閉原則 (OCP)工廠類別數量隨外掛增加而線性增長
版本管理內建,支援並存尚未解決外掛間相依性解析 (需引入 DI 容器)
介面隔離,利於單元測試生命週期管理 (OnLoad/Run/OnDestroy) 需宿主協調
支援宿主/擴充雙層架構安全性:未簽名驗證、沙箱隔離機制