前言 插件式架構,一種全新的、開放性的、高擴展性的架構體系。插件式架構設計好處很多,把擴展功能從框架中剝離出來,降低了框架的複雜度,讓框架更容易實現。擴展功能與框架以一種很松的方式耦合,兩者在保持介面不變的情況下,可以獨立變化和發佈。基於插件設計並不神秘,相反它比起一團泥的設計更簡單,更容易理解。 ...
前言
插件式架構,一種全新的、開放性的、高擴展性的架構體系。插件式架構設計好處很多,把擴展功能從框架中剝離出來,降低了框架的複雜度,讓框架更容易實現。擴展功能與框架以一種很松的方式耦合,兩者在保持介面不變的情況下,可以獨立變化和發佈。基於插件設計並不神秘,相反它比起一團泥的設計更簡單,更容易理解。
項目介紹
書寫4個插件類庫,分別傳參實現“加減乘除”運算,調用插件的客戶端採用Winform窗體程式。
目標框架:.NET Framework 4.6.1
項目架構和窗體佈局:
客戶端程式:
- PluginApp:反射調用插件
插件描述:
- PluginBase:規範插件的基類,定義抽象類,開發的插件的類需要繼承此類,代表遵守這個規範。
- CustomPlugInA:實現加法的插件
- CustomPlugInB:實現減法的插件
- CustomPlugInC:實現乘法的插件
- CustomPlugInD:實現除法的插件
代碼實現
插件基類
/// <summary>
///插件基類
/// </summary>
public abstract class Base
{
/// <summary>
/// 插件名稱
/// </summary>
/// <returns></returns>
public abstract string Name();
/// <summary>
/// 插件描述
/// </summary>
/// <returns></returns>
public abstract string Desc();
/// <summary>
/// 執行方法
/// </summary>
/// <param name="param1">參數1</param>
/// <param name="param2">參數2</param>
/// <returns></returns>
public abstract string Run(int param1, int param2);
/// <summary>
/// 版本
/// </summary>
public string Version
{
get { return "1.0.0"; }
}
}
PlugInA
public class PlugInA: Base
{
public override string Name()
{
return "PlugInA";
}
public override string Desc()
{
return "加法";
}
public override string Run(int param1,int param2)
{
return (param1 + param2) + "";
}
}
}
PlugInB
public class PlugInB : Base
{
public override string Name()
{
return "PlugInB";
}
public override string Desc()
{
return "減法";
}
public override string Run(int param1, int param2)
{
return (param1 - param2) + "";
}
}
PlugInC
public class PlugInC : Base
{
public override string Name()
{
return "PlugInC";
}
public override string Desc()
{
return "乘法";
}
public override string Run(int param1, int param2)
{
return (param1 * param2) + "";
}
}
PlugInD
public class PlugInD : Base
{
public override string Name()
{
return "PlugInD";
}
public override string Desc()
{
return "除法";
}
public override string Run(int param1, int param2)
{
return (param1 / param2) + "";
}
}
客戶端核心代碼:
public partial class FrmMain : Form
{
public FrmMain()
{
InitializeComponent();
dgrvPlugins.AutoGenerateColumns = false;
}
List<PluginModel> List = new List<PluginModel>();
readonly string PlugInPath = Application.StartupPath + "\\PlugIns";
/// <summary>
/// 載入插件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btLoadPlugins_Click(object sender, EventArgs e)
{
if (!Directory.Exists(PlugInPath))
{
Directory.CreateDirectory(PlugInPath);
}
List.Clear();
string[] files = Directory.GetFiles(PlugInPath);
foreach (string file in files)
{
if (file.ToLower().EndsWith(".dll"))
{
try
{
Assembly assembly = Assembly.LoadFrom(file);
Type[] types = assembly.GetTypes();
foreach (Type type in types)
{
if (type.BaseType.FullName == "PlugInBase.Base")
{
object obj = assembly.CreateInstance(type.FullName);
string name = type.GetMethod("Name").Invoke(obj, null).ToString();
string desc = type.GetMethod("Desc").Invoke(obj, null).ToString();
string version = type.GetProperty("Version").GetValue(obj).ToString();
List.Add(new PluginModel
{
Name = name,
Desc = desc,
Version = version,
type = type,
Obj = obj
});
}
}
}
catch (Exception ex)
{
throw ex;
}
}
}
dgrvPlugins.DataSource = new BindingList<PluginModel>(List);
}
/// <summary>
/// 打開插件目錄
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btOpenPluginDir_Click(object sender, EventArgs e)
{
Process.Start(PlugInPath);
}
/// <summary>
/// 執行選中插件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btExcute_Click(object sender, EventArgs e)
{
//獲取選擇的插件信息
int index = dgrvPlugins.CurrentRow.Index;
object obj = List[index].Obj;
Type type = List[index].type;
//參數
object[] inParams = new object[2];
inParams[0] =Convert.ToInt32( dgrvPlugins.CurrentRow.Cells[2].Value);
inParams[1] = Convert.ToInt32(dgrvPlugins.CurrentRow.Cells[3].Value);
object value = type.GetMethod("Run").Invoke(obj, inParams);
MessageBox.Show(Convert.ToString(value),"結果",MessageBoxButtons.OK);
}
}
項目配置
插件生成配置
編譯生成項目的時候需要註意,此處的調用插件是通過反射調用.dll中類和方法,所以首先要找到這個.dll的文件,所以此處我們在Winform客戶端程式下建立一個存放類庫dll的文件PlugIns
,在插件類庫項目生成後事件命令中,填入如下命令:
copy /Y "$(TargetDir)$(ProjectName).dll" "$(SolutionDir)\PlugIns"
以上命令代表,在項目的類庫生成後,將類庫copy到解決方案的路徑子文件夾PlugIns
,也就是我們建立存放自定義插件的文件夾。當然,如果不怕麻煩,每次生成後,手動複製到此文件夾也可以,直接複製到客戶端程式的..\bin\PlugIns
文件夾下。
插件路徑配置
全選這些類庫,把這些類庫設置為"如果較新則複製",這樣每次在編譯客戶端程式,如果自定義插件有更新,則同步會複製到bin
目錄下
插件基類配置
插件基類提供了規範,需要在類庫的生成後事件,添加命令:
copy /Y "$(TargetDir)$(ProjectName).dll" "$(SolutionDir)\bin\Debug"
將生成的dll文件,拷貝到客戶端程式的bin
路徑下
調用演示
CustomPlugInA
CustomPlugInB
CustomPlugInC
CustomPlugInD
插件開發優缺點
- 把擴展功能從框架中剝離出來,降低了框架的複雜度,讓框架更容易實現
- 宿主中可以對各個模塊解析,完成插件間、插件和主程式間的通信。
- 插件開發的可擴展性,靈活性比較高,而且可以進行定製化開發。
缺點
-
每一個插件被編譯成了dll,各模塊無法單獨運行,必須依托於主程式。
-
修改插件時,由於生成的是dll,無法快速直觀的查看修改以及調試。
-
每一個插件必須依賴於某一個規範。
本文來自博客園,作者:碼農阿亮,轉載請註明原文鏈接:https://www.cnblogs.com/wml-it/p/17706182.html
技術的發展日新月異,隨著時間推移,無法保證本博客所有內容的正確性。如有誤導,請大家見諒,歡迎評論區指正!
開源庫地址,歡迎點亮:
GitHub:https://github.com/ITMingliang
Gitee: https://gitee.com/mingliang_it
GitLab: https://gitlab.com/ITMingliang
建群聲明: 本著技術在於分享,方便大家交流學習的初心,特此建立【編程內功修煉交流群】,為大家答疑解惑。熱烈歡迎各位愛交流學習的程式員進群,也希望進群的大佬能不吝分享自己遇到的技術問題和學習心得!進群方式:掃碼關註公眾號,後臺回覆【進群】。