Links classes during configuration rather than compilation.
中文的意思是透過反射(reflection)機制於執行期(run time)由設定檔(configuration)取得實際要執行的物件,它在實作上有幾項特色
- 會有一個實作Factory Method Pattern的類別,用於生成實際要執行之物件(plugin object)
- 設定檔內會有實際生成物件的組件名稱及型別,如放置在App.config或Web.config的appSettings中
- 實際生成之物件必定實作一通用介面
以下以一範例說明如何實作Plugin Pattern,範例為實作一簡易的log機制,系統可允許一般文字log及XML格式log
1.建立一通用介面
public interface ILogger { void Write(Dictionary<string, string> messages); }
2.建立TextLogger類別(plugin object),並實作ILogger介面
public class TextLogger : ILogger { public void Write(Dictionary<string, string> messages) { StringBuilder sb = new StringBuilder(); messages.ToList().ForEach(c => sb.AppendLine(string.Format("{0}:{1}", c.Key, c.Value))); sb.AppendLine(); File.AppendAllText(string.Format("{0}.txt", DateTime.Now.ToString("yyyyMMdd")), sb.ToString()); } }
3.建立XmlLogger類別(plugin object) ,並實作ILogger介面
public class XmlLogger : ILogger { public void Write(Dictionary<string, string> messages) { XElement element = new XElement( new XElement("Record", new XElement("Action", messages["Action"]), new XElement("Detail", messages["Detail"]), new XElement("LogTime", messages["LogTime"]) ) ); File.AppendAllText(string.Format("{0}_{1}.xml", DateTime.Now.ToString("yyyyMMdd"), Guid.NewGuid()), element.ToString()); } }
4.建立一實作Factory Method Pattern的類別
public class LoggerFactory { private static ILogger _logger; public static ILogger CreateLogger() { if (_logger == null) { string assemblyName = ConfigurationManager.AppSettings["AssemblyName"]; string classType = ConfigurationManager.AppSettings["ClassType"]; Assembly assembly = Assembly.Load(assemblyName); _logger = assembly.CreateInstance(classType) as ILogger; } return _logger; } }
5.建立設定檔
<xml version="1.0" encoding="utf-8"> <configuration> <appsettings> <add key="AssemblyName" value="LoggerSample"> <add key="ClassType" value="LoggerSample.PluginPattern.TextLogger"> </appsettings> </configuration>
6.使用方式
ILogger log = LoggerFactory.CreateLogger(); Dictionary<string, string> messages = new Dictionary<string, string>(); messages.Add("Action", "建立使用者"); messages.Add("Detail", string.Format("UserId: {0}, UserName: {1}", user.UserId, user.UserName)); messages.Add("LogTime", DateTime.Now.ToString()); log.Write(messages);
7.若要切換log機制,僅須修改設定檔
<xml version="1.0" encoding="utf-8"> <configuration> <appsettings> <add key="AssemblyName" value="LoggerSample"> <add key="ClassType" value="LoggerSample.PluginPattern.XmlLogger"> </appsettings> </configuration>
以上為Plugin Pattern的實作步驟。事實上,在.NET Framework中已內建Plugin Pattern,稱為Provider Pattern,實作時plugin object需額外繼承ProviderBase類別,並自訂Provider用的設定檔區段(繼承ConfigurationSection),詳細的實作細節可參考Clark兄的文章Provider Pattern。
雖然Plugin Pattern在實作上很簡單,但在系統中可能不只像範例中只有log機制需要作抽換的動作,所以在實務上會以IoC(Inversion of Control) Pattern再搭配IoC Framework如StructureMap, Unity, Spring.NET等實作抽換機制。
範例程式下載
備註
原文修改自筆者於公司內部分享Plugin Pattern實作的簡報檔,可按此下載
No comments:
Post a Comment