其实我也常看到类似问题,我也回答过,说来也不难,反射,主程序提供一个固定的调用方法的功能,dll在加载后,能够提供一些函数,让主程序调用,加载到程序中,剩下的就各不相关了。比如:
App伪代码
public bool Load(string file)
{
    Assembly asmb = Assembly.LoadFrom(file);
    foreach(var c in asmb.GetTypes())
    {
        var enter = c.GetMethod("enter");
        if(enter == null) continue;
        enter.Invoke(...);
        return true;
    }
    return false
}这样,插件模块中,只要提供了enter,就可以被加载。就类似程序的main被启动一样了。或是提供一个dll,里面定义了所有的interface,程序使用这个dll中的接口,模块也引用这个dll,提供实现。这些可能都可行,又可能有问题。我没实际做过类似的功能。所以想请朋友们给些建议。另外,软件如果插件化,从逻辑上,插件本身需要低耦合,那么,这势必增加了主程序和插件之间的通讯难度?不知道我这样理解是不是因为我的设计不合理造成的。比如,我对A说,你去吧你的车开到某处接个人来。对B说,你开公司的车道某处接个人来。
这里,我知道A有车,B没车。所以我直接可以这样操作。
但如果接口化了,我就必须说:
找一个人来,判断一下这个人是否有车,根据结果选择一个操作去执行。这样就会复杂一些了。是不是?
意思是逻辑上,接口、插件的设计是更高一级的抽象,是否就一定的带来更多的逻辑复杂性呢?
在复述一下2个问题,免得我描述不清晰造成大量无意义回复:
1.插件化的软件,是如何架构的?请有经验的给些意见,建议。
2.什么功能适合插件化?是否必然的会带来逻辑复杂度上升?如何避免设计过度?

解决方案 »

  1.   

    至于方便,这个定义就要软件是什么个样子的了,如果才几K行代码的小软件,完全可以按照LZ所说的方式去弄,如果大一点的话,有一整套体系和结构还是比较好的,对大型软件完全木有概念,坐等高人讲解。
      

  2.   

    相对于 visual studio,DEV算是个插件了,
    这个插件很强大了
      

  3.   

    我们的插件是这样的
    主程序给插件dll提供一些公用的虚接口和类,界面上一切本插件相关的东西都由dll自己提供,例如ICON,按钮操作等,主程序专门做个DLL管理插件
      

  4.   

    我觉得关键在于主程序怎么设计,主程序是怎么展现的。比如Windows Live writer和它的代码高亮插件。主程序界面要做到模块化。
      

  5.   

    可以直接用现成的net4版微软已经把一个现成的插件机制MEF直接集成在框架里面了
      

  6.   

    不同于微软以前的几个插件机制,那几个都太复杂了现在这个MEF机制可以说是相当的简单
      

  7.   

    Developer Express .NET v8.2 我用的这个版本。没看到里面有啥插件 。OD插件非常多 。如果你想让别简单的扩充你的程序。你提供下接口。
    你不提供也没无谓。
    反正有钩子。
      

  8.   

    MEF 接分 = =不过现在的MEF使用起来还有若干问题 = =
      

  9.   


    MEF 像DI 多一些,和 Add-In 模型 划分的很清楚。
      

  10.   

    我也正在研究做插件化的方式来实现一个软件的设计,但不是用C#,用VC来做。
    这里有篇文章可以参考下的 http://www.cppblog.com/kenlistian/archive/2009/03/11/47753.html
      

  11.   

    看过wordpress,它会在某个功能的程序中添加一些代理或者事件,插件开发者可以对这些事件进行绑定,程序执行时触发自己的处理方法。
    这样做的前提就是要先定义哪些地方需要开放给插件。
      

  12.   

    楼主如果有时间的话可以研究一下sharpdevelop的源码。
    个人觉得这里的插件化机制挺不错的。
      

  13.   

    去年我为公司写了一个工具,当时领导明确要把它做成插件式,以后只需提供插件就可以继承到工具中。
    我当时的想法是这样的,主界面是个winform,上面有个MenuStrip,每一个MenuStripItem代表一个插件的功能。Winform的下部是个TabControl,当点击MenuStripItem下的子MenuStripItem时,就在TabControl里增加一个TabPage。首先我定义了两个接口:using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;namespace Contracts
    {
        public interface IAddIn
        {
            string AddInName { get; }
            IList<ITool> Tools { get; }
        }    public interface ITool
        {
            string ToolName { get; }
            Control UserInterface { get; }
            IList<ITool> SubTools { get; }
        }
    }IAddIn代表插件,ITool代表该插件下拥有的功能。然后插件实现这个接口,并生成一个winform类库,放到指定的一个目录下,然后我在工具的主程序里遍历这个目录,找到所有dll,反射看有哪些类实现了IAddIn接口,把它们加载到MenuStrip里:        void LoadAddIns()
            {
                string dir = Application.StartupPath + "\\AddIns\\";
                if (!Directory.Exists(dir))
                    Directory.CreateDirectory(dir);
                foreach (string d in Directory.GetDirectories(dir))
                {
                    foreach (string s in Directory.GetFiles(d))
                    {
                        if (Path.GetExtension(s) == ".dll")
                        {
                            try
                            {
                                //获取程序集,获取程序集下所有类,判断是否实现了IAddIn接口
                                Assembly ass = Assembly.LoadFile(s);
                                foreach (Type t in ass.GetTypes())
                                {
                                    if (Array.IndexOf(t.GetInterfaces(), typeof(IAddIn)) > -1)
                                    {
                                        IAddIn c = Activator.CreateInstance(t) as IAddIn;
                                        ToolStripMenuItem item = new ToolStripMenuItem(c.AddInName);
                                        item.Tag = c;
                                        BuildTree(item, c.Tools);
                                        menuStrip1.Items.Add(item);
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show(ex.Message);
                            }
                        }
                    }
                }
            }
      

  14.   

    插件编码是比直接耦合到APP中复杂些,复杂性换扩展性
      

  15.   

    我们公司正在开发一套软件开发平台,如果楼主对插件和模型这方面比较感兴趣的话,欢迎联系我们公司!!!
    iModel是由我公司开发的一款软件快速开发及运行平台。该平台所应用的方法是一种模型驱动的软件开发方法,它包括建模工具和模型运行引擎 ,建模工具用于设计和维护软件的基本模型和插件模型,模型引擎用于执行软件模型生成软件。iModel在通常的基本模型上增加了可用插件扩展其功能的接口。iModel的插件不同于一般意义上的插件,它是一种可以带参数的进一步扩展基本模型功能的可复用的软件组件。插件必须挂在基本模型对象上(也就是插件的主体对象),让主体对象实现一定的业务规则或者完成一定的功能。插件可以自动响应主体对象的消息并完成相关操作。
    iModel通过为插件建模定义把易变的插件应用和相对稳定的插件实现相分离,以实现一种能软件系统在运行态就可以通过对插件参数的调整而改变插件的内部运行状态的能力。
       iModel为软件开发者提供丰富的通用插件模型和插件实现,覆盖软件界面、功能,结构,流程等各方面;通过基础建模和大量插件的选择组装与集成可以实现软件系统的复杂逻辑功能和丰富界面表现。用户也可以很容易地在系统中增加插件模型及其实现完成对特殊功能的业务功能。
       iModel提供从建模、模型维护一整套工具及运行平台。不同角色的开发人员可以同时在此平台进行分工协同开发。iModel可以在运行态流畅地修改模型、调整插件并可以直接看到运行的效果。开发、运行、维护完全以模型为中心 
      

  16.   

    .net已经有官方的实现了.参考System.AddIn.
    不过我觉得那个太复杂.以前设计过类似的东西.不过那是还在学校的时候的实验品.
    代码已经找不到了囧.所以我只能描述一下了:首先插件和插件的宿主方有自定的接口.
    插件和宿主之间的通信通过接口定义实现沟通.`每一个插件都是一个类.(不要使用你例子里的伪代码那
    样的Invoke,那样除去设计上的糟糕不说,性能也会大打折扣)系统预定义了一系列的接口和类.用于描述dll中的插件.
    插件信息的描述使用CustomAttribute 的方式实现.
    可以使用反射获取这些信息生成一个PluginInfo.
    异或是由插件自己实现PluginInfo接口,来动态的生成
    插件信息(这样插件就能由.net dll 扩充至dll载入的脚本)
    插件本身使用一个PlugInAttribute来标识.系统提供以下的服务:
    插件dll的载入.使用反射遍历程序集里的类,将使用PluginAttribute
    标识的类找出来放入管理器.插件的注册.将一个type作为插件注册到管理器插件类的创建(插件类工厂)由插件管理器中创建出对应Type的实例系统维护一个插件管理器.可以对当前系统载入的插件进行查询和添
    加删除的集中管理.它实质上是一个key-value的映射.其中key 称为插
    件名.由PluginAttribute描述.value是一个delegate.系统默认提供一
    个将插件类实例化的delegate.但如前所说,完全可以由自己实现PluginInfo
    的方法来达到自定实例创建过程的目的.当classfactory收到创建一个
    名为name的实例的时候,它会检索到对应的delegate调用并将返回的
    对象回送给调用方.呃...大概就是这么个东西.整个系统就是一堆类工厂和命令模式的实现.
    最后写完后发现用处不大.而且宿主开发很烦,必须使用面向接口的设计.只有在写复杂架构的东西的时候才能体现出这样开发模式的优点.平时
    写点小项目小玩具什么的用这玩意纯属蛋疼.
      

  17.   

    原来用VC++做过一个,可以把自定义的工具条做成Dll,都放在一个固定的目录下,并都提供统一的初始接口函数和几个固定函数。由主程序初始时动态加载所有这个目录下的Dll,判断有没有初始接口,如果有就读取Dll里面的某些函数,创建出工具条,使用这些工具时执行Dll里的代码。
    感觉能用,但不太实用。小程序的话,直接做成一个程序更方便。大程序的话,这种方式也不太可靠,很有可能有的插件Dll没有遵守某些规定,导致程序崩溃或运行不正常。
    可能互不熟悉的团队独立开发,由必须整合在一起的时候会有用。比如C公司让A公司开发一部分功能,B公司也开发一部分功能,最后要整合在一起成为一个软件。但A公司和B公司互相不交流技术,这时可能会有点用吧。
      

  18.   

    以我们公司的产品为例,插件这个其实可以借助第三方语言。
    比如Lua, 51lua.dll 就可以配合上C#。
    你只需要给他提供接口就OK,至于一些小逻辑就不需要你操心了,这是双赢。例:
    接口:GetFileName();
         Copy(x,x);
    那lua自己只需要做一个简单的判断
    x = GetFileName();
    if x ~= "" then
       Copy(x,x);
    end这样C#的压力适当的减轻,你只需要判断如果文件不存在返回一个 空字符串或者null等,这就要自己去定义接口了
      

  19.   

    http://www.cnblogs.com/yufb/archive/2009/10/26/1589942.html
    这是我做的一个vs的插件。你想为别的软件做插件。方法很多。
    留接口,只是为了扩展方便罢了。
      

  20.   

       看看我写的文章吧:
    Windows平台下C++插件系统实现的几个关键技术问题及其解决思路     开源的话看看Firefox的实现吧。
      

  21.   

    SharpDevelop 插件式设计
      

  22.   

    可以给你个我以前做的项目框架。WinForm的插件系统。
      

  23.   

    音频软件这块有种vst插件,各种音频处理效果器都是插件形式,窗口管理、跟宿主通信啥的,可以参考下。是用c/c++写的……
    http://www.steinberg.net/en/company/developer.html
      

  24.   

    MEF不是简单的反射,而是极其复杂的反射。它针对部署在不同位置的应用程序(它也加载了其它应用程序所需要依赖的一系列必须的组件),而不是我们普通常见的反射那种仅仅针对当前应用程序中的一个附加文件。对于动态使用其它应用程序,利用MEF很值得,因为它足够简单,一般人则做不到这么周全。
      

  25.   

    我现在用的的方法其实跟楼主写的差不多。
    每个插件可以用tiemer控制,系统启动时加载后,取到任务就工作。
    没有任务就隔几秒找找。
    有新的组件加进来,改改配置文件即可。
      

  26.   

    显然只有COM能解决这个问题。
    比较典型的有鼎鼎大名的office,支持VBA调用,还支持dll的“嵌入”!
    当然,好点的商业软件如autocad等等,或者说支持二次开发的软件都是这种架构!
    但是,这是比较“古老”的技术,从90年代初ole到90年代中期(win95)com结构的成熟,后来几乎就没有什么改变,最近两年多了python,但是没有com它什么也干不了(不绝对啊,别较劲)!
    关于com的中文书,有几本奉为“宝典”的,其实真是垃圾,王道还是msdn,呵呵!
    最后,近5年com几乎被人淡忘了,但是都在用,也说明这种架构成熟了!就如汇编,还有人提吗?
      

  27.   

    一、 插件分为两种:通用性和共享性;
    二、使用Visual studio中的插件向导,可以很快开发出一个插件;
    三、注意插件构成;插件的文件构成;
    四、插件的部属机制;
    改天我在我的博客中详细进行说明(最近有些,要开发的软件太多);
      

  28.   

    我现在想开发Becky的插件,
    但是缺乏开发文档和资料,不知道哪位大侠,有相关的信息,提供一下。http://topic.csdn.net/u/20110605/22/62c93d47-b744-440c-a1e5-b7b1bf2ed32a.html
      

  29.   

    写过一个搜索MP3的,对于每个网站搜索解析方法都是一个DLL。主程序规定了接口,每个DLL去实现这个接口,吧DLL放到指定目录,运行时加载这些DLL,并调用方法,得到搜索结果。比较简单的东西了,复杂的没有做过,学习下。
      

  30.   

    个人经验,将一切插件视同服务,插件框架即能够快速获取需要的服务的框架。
    1.定义配置文件记录插件信息,里面记录所有插件信息,举个简单例子就是
    <Service Base="XXX.XXX.Services.IUserSecurity" Type="XXX.XXX.Services.UserSecurity,XXX.XXX" />
    里面的IUserSecurity及自己定义的插件接口,我们根据插件运行行为分为两类,初始化后直接运行的插件与初始化后等待用户调用的插件。比方初始化后等待用户调用的插件接口,我是这样定义的
    public interface IService
    {
    void Initialize();
    void Unload();
    event EventHandler Initialized;
    event EventHandler Unloaded;
    }
    并自己书写了所有插件的基类Service,所有服务需集成此基类。插件类重载initialize实现自己插件初始化代码,也需要重载unload方法提供服务卸载功能写自己插件框架的服务提供类ServiceProvider,他需具有
    1.实现服务容器,与操作方法,为了方便可以实现IServiceContainer接口
    2.实现解释自己定义的服务配置文件的方法,根据配置文件将服务加入服务容器
      

  31.   

    个人感觉,用插件DLL加JAVASCIPT,是不是可以实现几乎所有客户的功能了。
    问题是:如何将插件的DLL输出,自动向脚本公开,脚本引擎可以自动识别用户插件中提供的功能接口。