闲谈可插拔式应用程序的开发

简介:

很多软件都是可插拔的,最知名的便是微软的Windows操作系统。你可以在Windows操作系统上安装QQ,也可卸掉QQ,这便是可插拔。这里不谈Windows的实现,因为太过复杂。本文就谈谈管理软件的可插拔的实现。相对Windows操作系统,QQ就是它的一个插件。所以可以简单的将开发可插拔的软件分为两个部分。一个是主应用程序的开发,一个是插件的开发。

    比Windows小的,常见的可插拔的软件是MSN。MSN主应用程序由MS开发,还存在一些MSN插件开发商,国内好像也有不少,这些插件开发商通过在插件中植入广告获取利润。MS不可能提高源代码给这些开发商,那么MSN的主应用程序和MSN的插件是如何衔接起来的呢。我想应该是MS提供了一些接口和方法供开发商使用,估计有个api之类的东西,所以开发可插拔的应用系统分为三个部分。

1、主应用程序的开发

2、公用接口的开发

3、插件的开发

    了解了这些以后,下面通过一个实例来说明。这个实例的原则是可扩展性强,能向下兼用。

    业务需求是:老系统每当逢年过节的时候,会通过邮件给用户发送一些祝福的邮件。现在流行手机和MSN(QQ没有借口)之后,客户希望系统能通过手机短信和MSN的消息给用户送去祝福。现在我们需要开发手机短信和MSN留言两个插件,然后将它们安装到系统中去。

实现:

    为了简单起见,这里使用控制台应用程序,如果你有兴趣,可以修改成asp.net或者Windows Form的。

    定义两个接口:

public interface IPluginHost
{
    void AddMenuItem(string name, MenuItemClickedHandler clickHandler);
    void RegisterComponent<T>(T component) where T : class;
    void MailNotice(string messaage);
}
public delegate void MenuItemClickedHandler(string name);

 

  这个接口是主应用程序继承的,现在只有MailNotice功能, AddMenuItem是供插件调用的方法,创建一个菜单。RegisterComponent是插件向主应用程序提供一些方法。
public interface IPlugin
{
    void Initialize(IPluginHost pluginHost);
    void DoSomething();
}

    上面是插件的接口。

    在主应用程序中有一个加载插件的地方。这里的插件是dll,所以我通过反射去加载这些dll。

public void LoadPlugin()
{
    foreach (string fileName in Directory.GetFiles(Directory.GetCurrentDirectory() + "\\" + "Plugins", "*.dll"))
    {
        Assembly assembly = Assembly.LoadFile(fileName);
        foreach (Type pluginType in assembly.GetTypes())
        {
            if (!pluginType.IsPublic || pluginType.IsAbstract || pluginType.IsInterface)
                continue;
            Type concreteType = pluginType.GetInterface(typeof(IPlugin).FullName, true);

            if (concreteType != null)
            {
                IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType);
                plugin.Initialize(this);
                pluginList.Add(plugin);
                break;
            }
        }
    }
}

    主应用程序执行的代码如下:

void Start()
{
    //邮件发送祝福
    MailNotice("中秋快乐");
    //加载插件
    LoadPlugin();
    //运行插件
    if (pluginList.Count > 0)
    {
        foreach (IPlugin plugin in pluginList)
        {
            plugin.DoSomething();
        }
    }

    Console.ReadLine();
}

    运行结果如下:

hhqqqq

    开发两个插件,都继承IPlugin。

    手机短信通知插件:

public class PluginA : IPlugin
{

    public void Initialize(IPluginHost pluginHost)
    {
        IPluginHost myApplication = (IPluginHost)pluginHost;
        myApplication.AddMenuItem("Click me", OnClick);

    }
    private void OnClick(string name)
    {
        Console.WriteLine("Omg! You clicked me!");
    }

    public void DoSomething()
    {
        Console.WriteLine("手机短信通知:中秋快乐");
    }

}

 

    MSN通知插件:

public class PluginB : IPlugin
{

    public void Initialize(IPluginHost pluginHost)
    {
        IPluginHost myApplication = (IPluginHost)pluginHost;
        myApplication.AddMenuItem("Click me", OnClick);

    }
    private void OnClick(string name)
    {
        Console.WriteLine("Omg! You clicked me!");
    }

    public void DoSomething()
    {
        Console.WriteLine("MSN信息通知:中秋快乐");
    }

}

 

    插件的目录如下图:

kkkyyy

    运行效果:

kkk444

 

扩展性和兼容性:

    如果我想在主应用程序中添加一个ShowMessageBox方法。而且这个方法供插件调用。考虑到版本的兼容性,公开的接口是不能修改的。比如:将主应用程序的接口修改成:

public interface IPluginHost
{
    void AddMenuItem(string name, MenuItemClickedHandler clickHandler);
    void RegisterComponent<T>(T component) where T : class;
    T GetComponent<T>() where T : class;
    void MailNotice(string messaage);
    void ShowMessageBox(string message);
}

    那么如何实现呢,很简单,使用依赖注入的方式。添加下面接口:

public interface IMessageBoxHost
{
    void ShowMessageBox(string message);
}
 

 

    通过主应用程序的构造函数,将MessageBoxHost对下岗注入到主应用程序,在通过插件的构造函数,将其注入插件之中。

主应用程序的构造函数:

public Program(IMessageBoxHost messageBoxHostInstance)
{
    this.messageBoxHostInstance = messageBoxHostInstance;
}

 

    插件构造函数:

public PluginA(IMessageBoxHost messageBoxHost)
{
    this.messageBoxHost = messageBoxHost;
}

 

    修改实例化插件的代码:

IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType, new object[] { messageBoxHostInstance });

    这样我们对版本兼容有了保障。

总结:本文闲谈了可插拔应用程序的开发原理,文章的后面提供了插件和应用程序之间版本兼容的一种方案。有讨论才有进步,欢迎各位留言。






本文转自麒麟博客园博客,原文链接:http://www.cnblogs.com/zhuqil/archive/2010/09/04/Plugin-System.html,如需转载请自行联系原作者

相关文章
|
3月前
|
C# 开发者 测试技术
震惊!Xamarin 竟能如此构建跨平台应用程序,代码共享、界面设计与性能优化全攻略大揭秘!
【8月更文挑战第31天】在移动应用开发领域,跨平台工具日益受到青睐。Xamarin 是一款强大的工具,支持使用 C# 开发适用于 iOS、Android 和 Windows 的应用。通过安装 Visual Studio 或 Visual Studio for Mac,并创建 Xamarin 项目,开发者可以利用丰富的功能和工具进行开发。Xamarin 的主要优势在于代码共享,能够显著提高开发效率。
73 0
|
3月前
|
缓存 开发者 测试技术
跨平台应用开发必备秘籍:运用 Uno Platform 打造高性能与优雅设计兼备的多平台应用,全面解析从代码共享到最佳实践的每一个细节
【8月更文挑战第31天】Uno Platform 是一种强大的工具,允许开发者使用 C# 和 XAML 构建跨平台应用。本文探讨了 Uno Platform 中实现跨平台应用的最佳实践,包括代码共享、平台特定功能、性能优化及测试等方面。通过共享代码、采用 MVVM 模式、使用条件编译指令以及优化性能,开发者可以高效构建高质量应用。Uno Platform 支持多种测试方法,确保应用在各平台上的稳定性和可靠性。这使得 Uno Platform 成为个人项目和企业应用的理想选择。
63 0
|
3月前
|
内存技术
【软件开发流程控制文档】嵌入式应用软件在线升级功能软件概要设计
【软件开发流程控制文档】嵌入式应用软件在线升级功能软件概要设计
45 0
|
3月前
|
存储 内存技术
【软件开发流程控制文档】嵌入式应用软件在线升级功能软件需求规格书
【软件开发流程控制文档】嵌入式应用软件在线升级功能软件需求规格书
31 0
|
5月前
|
缓存 监控 算法
构建高性能Java应用的秘诀
构建高性能Java应用的秘诀
|
存储 数据采集 监控
谈谈嵌入式应用软件人机界面开发的菜单框架编写
谈谈嵌入式应用软件人机界面开发的菜单框架编写
100 0
|
数据采集 存储 设计模式
嵌入式软件应用程序开发框架浅见
嵌入式Linux系统上开发,其实和PC上的软件开发很类似,一个好的框架,能保证系统的稳定性,同时也能降低开发难度。
229 0
|
C#
小巧的日志记录组件 - 开源研究系列文章
  今天给大家带来一个小巧的日志记录组件LogHelper。这个组件是由Log4Net这个组件的由来而来的,不过只是写入.txt文本文件而已。如果能够对大家的项目有帮助那就更好了。   首先,打开.SLN解决方案,添加引用日志组件。
1009 0