分享
分销 收藏 举报 申诉 / 4
播放页_导航下方通栏广告

类型C++实现的一种插件体系结构.doc

  • 上传人:pc****0
  • 文档编号:9009833
  • 上传时间:2025-03-11
  • 格式:DOC
  • 页数:4
  • 大小:36KB
  • 下载积分:10 金币
  • 播放页_非在线预览资源立即下载上方广告
    配套讲稿:

    如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。

    特殊限制:

    部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。

    关 键  词:
    C++ 实现 一种 插件 体系结构
    资源描述:
    C++实现的一种插件体系结构 本文讨论一种简单却有效的插件体系结构,它使用C++,动态链接库,基于面向对象编程的思想。 首先来看一下使用插件机制能给我们带来哪些方面的好处,从而在适当时候合理的选择使用。 1, 增强代码的透明度与一致性:因为插件通常会封装第三方类库或是其他人编写的代码,需要清晰地定义出接口,用清晰一致的接口来面对所有事情。你的代码也不会被转换程序或是库的特殊定制需求弄得乱七糟。 2, 改善工程的模块化:你的代码被清析地分成多个独立的模块,可以把它们安置在子工程中的文件组中。这种解耦处理使得创建出的组件更加容易重用。 3, 更短的编译时间:如果仅仅是为了解释某些类的声明,而这些类内部使用了外部库,编译器不再需要解析外部库的头文件了,因为具体实现是以私有的形式完成。 4, 更换与增加组件:假如你需要向用户发布补丁,那么更新单独的插件而不是替代每一个安装了的文件更为有效。当使用新的渲染器或是新的单元类型来扩展你的游戏时,能过向引擎提供一组插件,可以很容易的实现。 5, 在关闭源代码的工程中使用GPL代码:一般,假如你使用了GPL发布的代码,那么你也需要开放你的源代码。然而,如果把GPL组件封装在插件中,你就不必发布插件的源码。 介绍 先简单解释一下什么是插件系统以及它如何工作:在普通的程序中,假如你需要代码执行一项特殊的任务,你有两种选择:要么你自己编写,要么你寻找一个已经存在的满足你需要的库。现在,你的要求变了,那你只好重写代码或是寻找另一个不同的库。无论是哪种方式,都会导致你框架代码中的那些依赖外部库的代码重写。 现在,我们可以有另外一种选择:在插件系统中,工程中的任何组件不再束缚于一种特定的实现(像渲染器既可以基于OpenGL,也可以选择Direct3D),它们会从框架代码中剥离出来,通过特定的方法被放入动态链接库之中。 所谓的特定方法包括在框架代码中创建接口,这些接口使得框架与动态库解耦。插件提供接口的实现。我们把插件与普通的动态链接库区分开来是因为它们的加载方式不同:程序不会直接链接插件,而可能是在某些目录下查找,如果发现便进行加载。所有插件都可以使用一种共同的方法与应用进行联结。 常见的错误 一些程序员,当进行插件系统的设计时,可能会给每一个作为插件使用的动态库添加一个如下函数类似的函数:PluginClass *createInstance(const char*); 然后它们让插件去提供一些类的实现。引擎用期望的对象名对加载的插件逐个进行查询,直到某个插件返回,这是典型的设计模式中“职责链”模式的做法。一些更聪明的程序员会做出新的设计,使插件在引擎中注册自己,或是用定制的实现替代引擎内部缺省实现: Void dllStartPlugin(PluginManager &pm); Void dllStopPlugin(PluginManager &pm); 第一种设计的主要问题是:插件工厂创建的对象需要使用reinterpret_cast<>来进行转换。通常,插件从共同基类(这里指PluginClass)派生,会引用一些不安全的感觉。实际上,这样做也是没意义的,插件应该“默默”地响应输入设备的请求,然后提交结果给输出设备。 在这种结构下,为了提供相同接口的多个不同实现,需要的工作变得异常复杂,如果插件可以用不同名字注册自己(如Direct3DRenderer and OpenGLRenderer),但是引擎不知道哪个具体实现对用户的选择是有效的。假如把所有可能的实现列表硬编码到程序中,那么使用插件结构的目的也没有意义了。 假如插件系统通过一个框架或是库(如游戏引擎) 实现,架构师也肯定会把功能暴露给应用程序使用。这样,会带来一些问题像如何在应用程序中使用插件,插件作者如何引擎的头文件等,这包含了潜在的三者之间版本冲突的可能性。 单独的工厂 接口,是被引擎清楚定义的,而不是插件。引擎通过定义接口来指导插件做什么工作,插件具体实现功能。我们让插件注册自己的引擎接口的特殊实现。当然直接创建插件实现类的实例并注册是比较笨的做法。这样使得同一时刻所有可能的实现同时存在,占用内存与CPU资源。解决的办法是工厂类,它唯一的目的是在请求时创建另外类的实例。如果引擎定义了接口与插件通信,那么也应该为工厂类定义接口: template<typename Interface> class Factory { virtual Interface *create() = 0; }; class Renderer { virtual void beginScene() = 0; virtual void endScene() = 0; }; typedef Factory<Renderer> RendererFactory; 选择1: 插件管理器 接下来应该考虑插件如何在引擎中注册它们的工厂,引擎又如何实际地使用这些注册的插件。一种选择是与存在的代码很好的接合,这通过写插件管理器来完成。这使得我们可以控制哪些组件允许被扩展。 class PluginManager { void registerRenderer(std::auto_ptr<RendererFactory> RF); void registerSceneManager(std::auto_ptr<SceneManagerFactory> SMF); }; 当引擎需要一个渲染器时,它会访问插件管理器,看哪些渲染器已经通过插件注册了。然后要求插件管理器创建期望的渲染器,插件管理器于是使用工厂类来生成渲染器,插件管理器甚至不需要知道实现细节。 插件由动态库组成,后者导出一个可以被插件管理器调用的函数,用以注册自己: void registerPlugin(PluginManager &PM); [NextPage] 插件管理器简单地在特定目录下加载所有dll文件,检查它们是否有一个名为registerPlugin()的导出函数。当然也可用xml文档来指定哪些插件要被加载。  选择 2: 完整地集成Fully Integrated 除了使用插件管理器,也可以从头设计代码框架以支持插件。最好的方法是把引擎分成几个子系统,构建一个系统核心来管理这些子系统。可能像下面这样: [Page] class Kernel { StorageServer &getStorageServer() const; GraphicsServer &getGraphicsServer() const; }; class StorageServer { //提供给插件使用,注册新的读档器 void addArchiveReader(std::auto_ptr<ArchiveReader> AL); // 查询所有注册的读档器,直到找到可以打开指定格式的读档器 std::auto_ptr<Archive> openArchive(const std::string &sFilename); }; class GraphicsServer { // 供插件使用,用来添加驱动 void addGraphicsDriver(std::auto_ptr<GraphicsDriver> AF); // 获取有效图形驱动的数目 size_t getDriverCount() const; //返回驱动 GraphicsDriver &getDriver(size_t Index); }; 这里有两个子系统,它们使用” Server”作为后缀。第一个Server内部维护一个有效图像加载器的列表,每次当用户希望加载一幅图片时,图像加载器被一一查询,直到发现一个特定的实现可以处理特定格式的图片。另一个子系统有一个GraphicsDrivers的列表,它们作为Renderers的工厂来使用。可以是Direct3DgraphicsDriver或是OpenGLGraphicsDrivers,它们分别负责Direct3Drenderer与OpenGLRenderer的创建。引擎提供有效的驱动列表供用户选择使用,通过安装一个新的插件,新的驱动也可以被加入。 版本 在上面两个可选择的方法中,不强制要求你把特定的实现放到插件中。假如你的引擎提供一个读档器的默认实现,以支持自定义文件包格式。你可以把它放到引擎本身,当StorageServer 启动时自动进行注册。 现在还有一个问题没有讨论:假如你不小心的话,与引擎不匹配(例如,已经过时的)插件会被加载。子系统类的一些变化或是插件管理器的改变足 以导致内存布局的改变,当不匹配的插件试图注册时可能发生冲突甚至崩溃。比较讨厌的是,这些在调试时难与发现。 幸运的是,辨认过时或不正确的插件非常容易。最可靠的是方法是在你的核心系统中放置一个预处理常量。任何插件都有一个函数,它可以返回这个常量给引擎: // Somewhere in your core system #define MyEngineVersion 1; // The plugin extern int getExpectedEngineVersion() { return MyEngineVersion; } 在这个常量被编译到插件后,当引擎中的常量改变时,任何没有进行重新编译的插件它的 getExpectedEngineVersion ()方法会返回以前的那个值。引擎可以根据这个值,拒绝加载不匹配的插件。为了使插件可以重新工作,必须重新编译它。当然,最大的危险是你忘记了更新常量值。无论如何,你应该有个自动版本管理工具帮助你。
    展开阅读全文
    提示  咨信网温馨提示:
    1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
    2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
    3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
    4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
    5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
    6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。

    开通VIP折扣优惠下载文档

    自信AI创作助手
    关于本文
    本文标题:C++实现的一种插件体系结构.doc
    链接地址:https://www.zixin.com.cn/doc/9009833.html
    页脚通栏广告

    Copyright ©2010-2026   All Rights Reserved  宁波自信网络信息技术有限公司 版权所有   |  客服电话:0574-28810668    微信客服:咨信网客服    投诉电话:18658249818   

    违法和不良信息举报邮箱:help@zixin.com.cn    文档合作和网站合作邮箱:fuwu@zixin.com.cn    意见反馈和侵权处理邮箱:1219186828@qq.com   | 证照中心

    12321jubao.png12321网络举报中心 电话:010-12321  jubao.png中国互联网举报中心 电话:12377   gongan.png浙公网安备33021202000488号  icp.png浙ICP备2021020529号-1 浙B2-20240490   


    关注我们 :微信公众号  抖音  微博  LOFTER               

    自信网络  |  ZixinNetwork