插件(Plugin)模式向用户提供了一种扩展程序的接口,用户可以在程序本体之外,按照指定接口编写插件来为程序增加功能。
可能实际开发中不太会运用到插件模式,但是它确实我们经常会使用到的一种模式。例如CocosBuilder和Unity3D都不同程度的提供了插件功能,用户可以自己编写插件来完善或者定制编辑器。此外,我们也可以编写Visual Studio、XCode或Eclipse的插件来扩展这些IDE。
插件模式中会有一个管理器用来管理这些插件,而如何调用插件的方法?这里我们就需要制定一个接口,插件必须实现接口方法,而管理器则调用这些方法。
插件抽象类:
public abstract class Plugin{public virtual void DoSomeThing (){}
}
如何知道插件的类型并实例化它们呢?我们可以使用反射(参考C#语法小知识(十)反射)+配置文件的方法来解决这个问题。
插件管理器:
public static class PluginManager
{private static Dictionary<string, Plugin> _plugins = new Dictionary<string, Plugin>();public static void LoadPlugin(string assemblyName, string typeStr){string key = assemblyName + typeStr;if (_plugins.ContainsKey (key)) {return;}var oh = System.Activator.CreateInstance (assemblyName, typeStr);object instance = oh.Unwrap ();_plugins [key] = (Plugin)instance;}public static void UnloadPlugin(string assemblyName, string typeStr){string key = assemblyName + typeStr;if (_plugins.ContainsKey (key)) {_plugins.Remove (key);}}public static void UnloadAllPlugins(){_plugins.Clear ();}public static void RunPlugins(){foreach (var kv in _plugins) {kv.Value.DoSomeThing ();}}
}
(示例中没有实现读取文件并加载插件的方法,需要根据实际情况来编写具体代码)
我们可以编写一个dll文件,并且添加测试插件:
public class TestPlugin : Plugin
{public override void DoSomeThing (){Console.WriteLine ("Test plugin");}
}
测试:
PluginManager.LoadPlugin ("xxx.dll", "TestPlugin");PluginManager.RunPlugins ();
插件模式的好处:
1、提供了扩展程序的可能。
2、将插件与事件发布者的耦合集中到插件管理器当中去,事件发布者并不需要知道插件中的具体逻辑,只负责发送事件。
3、增加插件也很方便。
缺点在于,使用插件模式扩展程序,往往需要使用反射,这样就会影响程序的执行速度。