分享
为什么问答平台  ›  专栏  ›  技术社区  ›  justkt

如何创建一个灵活的插件架构? - How To Create a Flexible Plug-In Architecture?

  •  137
  • justkt  · 技术社区  · 2 月前

    在我的开发工作中,重复的主题是使用或创建内部插件架构。我看到它有很多种方法——配置文件(XML,.conf等)、继承框架、数据库信息、库等。根据我的经验:

    • 数据库不是存储配置信息的好地方,尤其是与数据混合的地方。
    • 尝试使用继承层次结构进行此操作需要了解要编码的插件,这意味着插件体系结构并不是那么动态。
    • 配置文件可以很好地提供简单的信息,但不能处理更复杂的行为。
    • 库似乎工作得很好,但是必须小心地创建单向依赖项。

    当我试图从我工作过的各种架构中学习时,我也在向社区寻求建议。您是如何实现一个可靠的插件架构的?你最严重的失败是什么(或你见过的最严重的失败)?如果要实现一个新的插件架构,您会怎么做?您所使用的哪个SDK或开放源码项目具有良好体系结构的最佳示例?

    我自己发现的几个例子:

    这些例子似乎发挥了各种语言的优势。一个好的插件架构是否一定与语言相关?是最好使用工具来创建一个插件架构,还是在自己的后续模型上这样做?

    8 回复  |  直到 2 月前
        1
  •  77
  •   Noufal Ibrahim    4 年前

    这不是一个 回答 以及一堆可能有用的评论/例子。

    • 使应用程序可扩展的一个有效方法是将其内部作为脚本语言公开,并用该语言编写所有顶级内容。这使得它非常可修改,而且实际上是未来的证明(如果您的原语被很好地选择和实现的话)。这种事情的成功故事是Emacs。我更喜欢Eclipse风格的插件系统,因为如果我想扩展功能,我不需要学习API和编写/编译单独的插件。我可以在当前缓冲区中编写一个3行代码片段,对其进行评估并使用它。学习曲线非常流畅,效果非常好。

    • 我已经扩展了一点的应用程序是 Trac . 它有一个组件体系结构,在这种情况下,这意味着任务被委托给宣传扩展点的模块。然后,您可以实现适合这些点的其他组件,并更改流。这有点像上面卡基的建议。

    • 另一个好的是 py.test . 它遵循“最好的API不是API”的理念,完全依赖于在每个级别调用的钩子。您可以在根据约定命名的文件/函数中重写这些挂钩,并更改行为。您可以在站点上看到插件列表,以了解它们的实现速度和容易程度。

    几个要点。

    • 尽量保持您的非扩展/非用户可修改核心尽可能小。把你能做的一切委托给一个更高的层,这样扩展性就增加了。减少核心问题的纠正,以防出现错误的选择。
    • 与上述观点相关的是,在一开始就不应该对项目的方向做太多的决定。实现所需的最小子集,然后开始编写插件。
    • 如果您要嵌入脚本语言,请确保它是完整的,您可以在其中编写常规程序,而不是玩具语言。 只是 为您的申请。
    • 尽可能减少样板文件。不要费心子类化、复杂的API、插件注册和类似的事情。尽量保持简单,这样 容易的 而不仅仅是 可能的 延伸。这将使您的插件API得到更多的使用,并鼓励最终用户编写插件。不仅仅是插件开发人员。py.test做得很好。据我所知,日食 does not .
        2
  •  23
  •   Nyight    4 年前

    根据我的经验,我发现实际上有两种类型的插件架构。

    1. 一个跟随 Eclipse model 它是为了自由而开放的。
    2. 另一个通常需要插件遵循 narrow API 因为插件将填充特定的函数。

    以另一种方式陈述这一点, 允许插件访问您的应用程序 而另一个 允许应用程序访问插件 .

    区别是微妙的,有时没有区别…您的应用程序需要两者。

    我对Eclipse/打开你的应用到插件模型没有太多的经验(Kalkie的文章很棒)。我读过一些关于Eclipse做事情的方法,但没有什么比这更重要的了。

    耶奇 properties blog 稍微讨论一下属性模式的使用如何允许插件和可扩展性。

    我所做的大部分工作都是使用插件架构来允许我的应用访问插件,比如时间/显示/地图数据等。

    几年前,我会创建工厂、插件管理器和配置文件来管理所有的插件,并让我决定在运行时使用哪个插件。

    • 现在我通常只有一个 DI framework 做大部分的工作。

    我仍然需要编写适配器来使用第三方库,但它们通常没有那么糟糕。

        3
  •  13
  •   Patrick    9 年前

    我见过的最好的插件架构之一是在Eclipse中实现的。与使用插件模型的应用程序不同,一切都是插件。基本应用程序本身就是插件框架。

    http://www.eclipse.org/articles/Article-Plug-in-architecture/plugin_architecture.html

        4
  •  8
  •   Ian Ringrose    9 年前

    我曾经在一个项目中工作过,这个项目必须在每个客户设置系统的方式上如此灵活,我们找到的唯一好的设计就是向客户提供一个C编译器!

    如果规范中包含以下文字:

    • 柔性的
    • 插件
    • 可定制的

    像我的经验一样,询问很多关于您将如何支持系统的问题(以及如何收取支持费用,因为每个客户都会认为他们的案例是正常的,不需要任何插件)。

    客户的支持(或 fount line支持人们)写作 插件比 建筑

        5
  •  7
  •   BALKANGraph    9 年前

    通常我用mef。托管扩展性框架(简称MEF)简化了可扩展应用程序的创建。MEF提供了可以用来加载应用程序扩展的发现和组合功能。

    如果你感兴趣,请阅读 more...

        6
  •  6
  •   Dima Malenko    9 年前

    我将描述一个我过去使用过的相当简单的技术。这种方法使用C反射来帮助插件加载过程。这种技术可以被修改,因此它适用于C++,但是你失去了能够使用反射的便利性。

    IPlugin 接口用于标识实现插件的类。方法被添加到接口中,以允许应用程序与插件通信。例如 Init 应用程序将用于指示插件初始化的方法。

    要查找插件,应用程序将扫描.NET程序集的插件文件夹。每个组件都已加载。反射用于扫描实现 插件接口 . 将创建每个插件类的实例。

    (或者,XML文件可能列出要加载的程序集和类。这可能有助于提高性能,但我从未发现性能问题)。

    这个 初始化 为每个插件对象调用方法。它被传递到实现应用程序接口的对象的引用: IApplication (或其他特定于应用程序的名称,如ITexteditorApplication)。

    I应用 包含允许插件与应用程序通信的方法。例如,如果您正在编写文本编辑器,则此接口将具有 OpenDocuments 允许插件枚举当前打开的文档集合的属性。

    这个插件系统可以通过创建一个派生的插件类(例如Lua)扩展到脚本语言。 LuaPlugin 那个前锋 插件接口 函数和Lua脚本的应用程序接口。

    此技术允许您迭代地实现 插件接口 , I应用 以及开发期间的其他特定于应用程序的接口。当应用程序完成并很好地重构后,您可以记录您公开的接口,并且您应该有一个好的系统,用户可以为其编写自己的插件。

        7
  •  3
  •   Justin    9 年前

    我认为你需要首先回答这个问题:“什么组件是插件?” 您希望将这个数字保持在绝对最小值或必须测试爆炸的组合数。尝试将核心产品(不应该有太多的灵活性)与插件功能分开。

    我发现ioc(控制反转)主体(read springframework)在提供灵活的基础上工作得很好,您可以添加专门化来简化插件开发。

    • 您可以扫描容器中的“Interface as a Plugin Type Advertise”机制。
    • 您可以使用容器注入插件可能需要的公共依赖项(即ResourceLoaderware或MessageSourceAware)。
        8
  •  3
  •   Jon Purdy    9 年前

    根据我的经验,创建灵活插件体系结构的两种最好方法是脚本语言和库。这两个概念在我看来是正交的;这两个概念可以以任何比例混合在一起,就像函数式和面向对象的编程一样,但在平衡时会发现它们的最大优势。图书馆通常负责实现特定的 界面 使用动态功能,而脚本倾向于强调 功能 具有动态界面。

    我发现一种基于 脚本管理库 似乎效果最好。脚本语言允许对较低级别的库进行高级操作,因此库可以从任何特定的接口中释放出来,从而将所有应用程序级交互都留在脚本系统更灵活的手中。

    为了实现这一点,脚本系统必须有一个相当健壮的API,它具有应用程序数据、逻辑和GUI的钩子,以及从库中导入和执行代码的基本功能。此外,脚本通常需要 安全的 从这个意义上说,应用程序可以优雅地从写得不好的脚本中恢复。使用脚本系统作为间接层意味着应用程序可以更容易地在发生坏的情况下分离自己。

    插件的打包方式在很大程度上取决于个人喜好,但是你绝不能用一个简单的界面来处理压缩的归档文件,比如 PluginName.ext 在根目录中。