推 Syung1983:感謝大大的範例,先研究看看 09/29 09:17
※ 引述《Syung1983 (小永)》之銘言:
: 請問一下 應用程式可新增功能,類似plugin的方法如何實作?
: 舉例來說有功能 A、B、C、D、E等模組,模組間互相獨立或相依
: 使用者如果需要A的功能,則安裝A模組就好。
: 如果需要C跟D的功能,則安裝這兩個模組就可以給另一位使用者
: 請問網路上有在討論此種作法的網站嗎?
: 目前我從網路上找到的資料只有
: Michael Tsai大所提到的: 動態型別應用例:動態載入 DLL模組
: 請問一下如果要搜尋的關鍵字應該使用什麼
要做 plug-in,首先你要搞清楚有什麼 function 和 proerty
甚至是 delegate 是需要共用的
然後你必需把它們訂成 interface,並且實作它編成 class library dll
舉個我以前有個做到一半的網路相簿下載器當例子:
(
真的有興趣的,完整的 source code 在 SourceForge 上
http://t-photo-ripper.svn.sourceforge.net/viewvc/t-photo-ripper/
Code 應該是可以 build,不過上面的 plug-in 應該都因為太久沒更新而沒用了
)
首先我訂出了一個 IPhotoRipperPlugIn 的 interface
這是所有的下載 plug-in 都必需要實作的 function 以及 property
public interface IPhotoRipperPlugIn
{
string PlugInName { get; }
string Author { get; }
string TargetSiteURL { get; }
URLType GetURLType(string aURL);
AlbumList GetAlbumList(string aURL, string aReferer);
AlbumList GetAlbumList(string aURL, string aReferer,
string aUsername, string aPassword);
AlbumPicList GetAlbumPicList(string aURL, string aReferer);
AlbumPicList GetAlbumPicList(string aURL, string aReferer,
string aUsername, string aPassword);
string GetLoginedCookie(string aUsername, string aPassword);
}
舉一個簡單的例子來說,每一個 PlugInName 都必需要實作 TargetSiteURL property
這樣才能透過問每個 plugin 的 TargetSiteURL,來得知 plugin 是針對哪個網站的
接下來是實作:
// PlugIn.cs (1)
namespace TPhotoRipperPlugIn
{
public class PlugIn : IPhotoRipperPlugIn
{
public string PlugInName
{
get { return "KTXP"; }
}
public string TargetSiteURL
{
get { return "http://comic.ktxp.com/"; }
}
}
}
// PlugIn.cs (2)
namespace TPhotoRipperPlugIn
{
public class PlugIn : IPhotoRipperPlugIn
{
public string PlugInName
{
get { return "DMZJ"; }
}
public string TargetSiteURL
{
get { return "http://comic.dmzj.com/"; }
}
}
}
像上面的情形你問 PlugIn (1) 它的 TargetSiteURL 就會是 http://comic.ktxp.com/
PlugIn (2) 就會回答你 http://comic.dmzj.com/
這當然只是節錄,真的 class 要把整個 interface 的東西都實作完
這兩個 class 分屬兩個 plug-in,為了方便載入起見,兩個 plug-in 的實作 class
都叫做 PlugIn,並且都位於 TPhotoRipperPlug namesapce 下
接下來是實際載入的部分
public class TPhotoRipperPlugInLoader
{
private Assembly _asmb;
private Object _obj;
private IPhotoRipperPlugIn _plugIn;
private string _lastError;
public TPhotoRipperPlugInLoader(string aPlugInPath)
{
if (!File.Exists(aPlugInPath))
{
_lastError = "DLL file not exists.";
return;
}
try
{
// 由 Assembly.LoadFrom 載入 dll 檔案
// 並產生 Assembly
_asmb = Assembly.LoadFrom(aPlugInPath);
if (_asmb == null)
{
_lastError = "Load PlugIn assembly failed";
return;
}
//由 CreateInstance 建立一個宣告在
//TPhotoRipperPlugIn namespace 下
//名字叫做 PlugIn 的 class 的實體物件
_obj = _asmb.CreateInstance(
"TPhotoRipperPlugIn.PlugIn"
);
//由該物件 query 出 plugin 共通的 interface
_plugIn = (IPhotoRipperPlugIn)_obj;
}
catch (Exception e)
{
_lastError = e.Message;
}
}
public bool isReady { get { return _plugIn != null; } }
public bool hasError { get { return _lastError != ""; } }
public string lastError { get { return _lastError; } }
// 由此 property 就可以使用 query 出來的 IPhotoRipper interface
public IPhotoRipperPlugIn plugIn { get { return _plugIn; } }
}
不過這只是單一用途 plug-in,其它多種類 plug-in 串連基本上差不多
但是要考慮的東西就更多了,多種的宣告可能會像這樣
interface IURLFetcher
{
string Fetch(string URL);
}
interface IURLParser
{
string PlugInName {get;}
void SetURLFetcherPlugIn(interface IURLFetcher);
}
由多個 interface 組合起來
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 112.104.91.27
※ 編輯: toki 來自: 112.104.91.27 (09/25 00:27)
※ 編輯: toki 來自: 112.104.91.27 (09/25 00:28)