小雉配置--支持向上向下兼容的 配置文件 兼容性 设计

这篇具有很好参考价值的文章主要介绍了小雉配置--支持向上向下兼容的 配置文件 兼容性 设计。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概述

      软件的开发离不开配置,传统的软件设计包括前端、后台和数据库3部分,三者是密切配合的统一整体,在实际项目中往往遇到以下问题:

  1. 因项目需求不明而增加、修改、删除参数导致配置结构调整后难以同已有数据兼容;
  2. 后台参数修改后,前端需要同步修改,无法做到老版本前端与新版本后台配合(新版本后台可能修正了bug,老版本前端属于老项目),修正老项目bug需要在老版本分支上进行,代码分支多,维护困难;
  3. 配置备份困难。首先后台与数据库之间有多个访问渠道,配置备份需要停机备份;其次备份的配置无法线上热还原(有差异部分相关模块重置,无修改部分持续工作,如仅1相机参数有区别,仅停掉1相机进行重连,其余相机持续工作);最后备份的配置无法在新版本或老版本上进行还原(因为字段结构不一样);
  4. 授权困难,配置臃肿。为实现所有用户需求,软件的参数量非常庞大,而对一个具体项目可能只需要其中的很少只关联10个参数的功能,把大量的参数置于系统中会拖慢系统(一个表只有1列可以允许插入1亿行,但如有1000列,可能表就只能插入10万行了)同时软件中需要通过授权判断而限制用户在授权范围内操作,系统调试困难--授权是在做一个减法操作;

思考与假设

      “小雉视频系统”是一套集所有客户需求于一体的一套视频软件,参数的修改随客户的要求变化而变化,均为不可预知的参数需求,为每位客户单独开一个分支会增加bug修正的同步成本和升级包制作成本,“小雉视频系统”迫切需要一套廉价的高效率的配置设计方案,要求方案具备如下特性:

  1. 配置项在各个模块中申明(限制值的类型、范围、个数和有效条件(比如A参数必须要B参数为1时才有效可设置)),在模块中读取,把参数的管理放到各个模块中,各个模块只需要根据本模块的需要申明参数,实现参数的模块化(移除此模块也移除了此模块的参数);
  2. 各个模块申明配置项时如同全新开发一样申明参数即可,同历史参数的兼容归配置模块算法实现;
  3. 各个模块如果未被授权,则不申明参数,通过减少参数增加系统的容量及并发,既功能少,并发高,让授权是一个加法操作;
  4. 申明参数时指定默认值,在客户端传参时未有对应参数时读取此参数时读到的值为默认值,以此实现对历史客户端的兼容(历史客户端与新版本后台字段有差异部分使用默认值代替,保证新后台可同老客户端适配);
  5. 申明参数时同时申明中文名、注释、可选值,即把注释写入配置,在配置导出时可自动对参数注释,实现文档源码化;
  6. 配置可以热导出,导出后的配置可热导入到任意版本的后台,配置模块可自动探测到变化,自动完成对象实例的增删改动作;
  7. 配置可以导出xml,json等格式,并支持xml,json的导入;
  8. 配置可导出非默认值部分字段,也能导入,实现瘦客户端编程(服务器可以集所有功能与一体,但针对具体的项目客户,可能只需要部分功能,可在完整客户端上正确配置对应项目需求的功能参数后导出参数,瘦客户端上只针对导出参数进行开发,减少参数可提高客户端的人性化程度);

小雉配置解决方案

      基于假设“小雉配置”采用面向属性的配置设计方式,把配置项分为节点型、模板、字符串、整型、浮点和二进制共6种数据类型,每种数据类型可设置多个条件组,以条件组内的所有条件为真此条件组为真,任何一个条件组为真则参数有效;
      “小雉配置”采用C语言编写,可用于windows,linux,arm等平台,配置为单文件,本地可拷贝备份,远程可热导入导出xml和json,配置可承载数千参数(结构可类似xml任意层级嵌套)数十万级别的量(类比一张表有上千列,表可以容纳数十万行);


小雉配置数据类型

  1. 节点型类型
          类似于xml中的a->b->c,其中b节点包含c,则b为节点型类型,且a下面有且只能有一个b;节点型类型可以作为节点型节点和模板节点的子类型,可以设置中文名、注释、条件判断,不能设置默认值,可选值;

    fs_Config_node_node_add //添加节点型参数
    fs_Config_node_get_first //获取节点型参数
  2. 模板类型
          类似于xml中的a->b->c,其中b节点包含c,如b固定且只有一个则b为节点型类型,如b可以是0到多个,则b为模板类型,申明模板实质是申明一个类,配置时在a下创建此类的多个实例(创建多少个实例,a下有多少个b,b的子节点与类的结构完全相同);模板类型主要用于同类型数据的管理(比如添加相机);模板类型可以作为节点型节点和模板节点的子类型,可以设置中文名、注释、条件判断、可创建实例的个数、时间控制参数(比如有两个模板实例,第一个模板实例在0-7点生效,另外一个在7-24时生效,实现参数随时间变化的控制),不能设置默认值,可选值;

    fs_Config_node_template_add //添加节点型参数
    fs_Config_node_template__IO //获取节点型参数
  3. 字符串类型
          字符串类型是一个储存字符串数据的节点类型;字符串类型可以作为节点型节点和模板节点的子类型,可以设置中文名、注释、条件判断、可设置值的个数、字符串长度、默认值、可选值;

    fs_Config_node_string_add //添加字符串类型参数
    fs_Config_node_string_get_first //获取字符串类型参数
  4. 整型类型
          整型类型是一个储存64位有符号整数的节点类型;整型类型可以作为节点型节点和模板节点的子类型,可以设置中文名、注释、条件判断、可设置值的个数、值的范围、默认值、可选值;

    fs_Config_node_integer_add //添加整型类型参数
    fs_Config_node_integer_get_first //获取整型类型参数
  5. 浮点类型
          浮点类型是一个储存64位浮点的节点类型;浮点类型可以作为节点型节点和模板节点的子类型,可以设置中文名、注释、条件判断、可设置值的个数、值的范围、默认值、可选值;

    fs_Config_node_float_add //添加浮点类型参数
    fs_Config_node_float_get_first //获取浮点类型参数
  6. 二进制类型
          二进制类型是一个储存任意数据类型的节点类型;二进制类型可以作为节点型节点和模板节点的子类型,可以设置中文名、注释、条件判断、可设置值的个数、数据长度范围、默认值、可选值;

    fs_Config_node_binary_add //添加二进制类型参数
    fs_Config_node_binary_get_first //获取二进制类型参数
    

小雉配置的简单演示

int main() {
// 创建配置
FsConfig * const pConfig = fs_Config_new__IO();
// 创建一个节点型节点
void *const node = fs_Config_node_node_add(pConfig, pConfig, "node", "节点", "测试节点", 0, 0x7);
{
    /* 在node下创建一个字符串节点,节点可以设置2个值,长度为0到10个字节 */
    void *const testString = fs_Config_node_string_add(pConfig, node, "testString", "测试字符串", "测试字符串", 0, 0x7, 0, 10, 2);
    /* 为testString添加一个default1的默认值 */
    fs_Config_node_string_add_value(pConfig, testString, FsConfig_nodeValue_default, "default1", "默认值1", "默认值1");
    /* 为testString添加一个optiona1的可选值 */
    fs_Config_node_string_add_value(pConfig, testString, FsConfig_nodeValue_optional, "optiona1", "可选值1", "可选值1");
    /* 在node下创建一个整型节点,节点可以设置2个值,取值范围为0到666666 */
    void *const testInt = fs_Config_node_integer_add(pConfig, node, "testInt", "测试整数", "测试整数", FsConfig_nodeShowType_default, 0, 0x7, 0, 666666, 2);
    /* 为testInt添加一个0的默认值 */
    fs_Config_node_integer_add_value(pConfig, testInt, FsConfig_nodeValue_default, 0, "0", "0");
    /* 为testInt添加一个100的可选值 */
    fs_Config_node_integer_add_value(pConfig, testInt, FsConfig_nodeValue_optional, 100, "100", "100");
    /* 在node下创建一个浮点节点,节点可以设置3个值,取值范围为0.0到1.0 */
    void *const testFloat = fs_Config_node_float_add(pConfig, node, "testFloat", "测试浮点", "测试浮点", 0, 0x7, 0.0, 1.0, 3);
    /* 为testFloat添加一个0.0的默认值 */
    fs_Config_node_float_add_value(pConfig, testFloat, FsConfig_nodeValue_default, 0.0, "0.0", "0.0");
    /* 为testFloat添加一个1.0的可选值 */
    fs_Config_node_float_add_value(pConfig, testFloat, FsConfig_nodeValue_optional, 1.0, "1.0", "1.0");
    /* 在node下创建一个二进制节点,节点可以设置2个值,长度为0到100个字节 */
    void *const testBinary = fs_Config_node_binary_add(pConfig, node, "testBinary", "测试二进制", "测试二进制", 0, 0x7, 1, 100, 2);
    /* 为testBinary创建一个条件组 */
    void *const condition_testBinary = fs_Config_condition_group_add(pConfig, testBinary);
    /* 向condition_testBinary添加一个条件,相对于testBinary节点向上一级的父节点中查找testInt节点,在testInt的值为0时此值有效 */
    fs_Config_condition_add_static(pConfig, condition_testBinary, 1, "testInt", FsConfig_Condition_equal, "0");
}
// 创建一个可以创建100个实例的模板
void *const template = fs_Config_node_template_add(pConfig, pConfig, "testTemplate", "测试模板", NULL, NULL, "测试模板", NULL, NULL, NULL, 0, 0x7, 100);
{
    /* 在template下创建一个字符串节点,节点可以设置2个值,长度为0到10个字节 */
    void *const testString1 = fs_Config_node_string_add(pConfig, template, "testString1", "测试字符串1", "测试字符串1", 0, 0x7, 0, 10, 2);
    /* 为testString1添加一个默认值 */
    fs_Config_node_string_add_value(pConfig, testString1, FsConfig_nodeValue_default, "default1", "默认值1", "默认值1");
    /* 为testString1添加一个可选值 */
    fs_Config_node_string_add_value(pConfig, testString1, FsConfig_nodeValue_optional, "optiona1", "可选值1", "可选值1");
    /* 在template下创建一个字符串节点,节点可以设置2个值,长度为0到10个字节 */
    void *const testString2 = fs_Config_node_string_add(pConfig, template, "testString2", "测试字符串2", "测试字符串2", 0, 0x7, 0, 10, 2);
    /* 为testString2创建一个条件组 */
    void *const condition_testString2 = fs_Config_condition_group_add(pConfig, testString2);
    /* 向condition_testString2添加一个条件,相对于testString2节点向上两级的父节点中查找node节点,再在node节点中查找testInt节电,在testInt的值为0时此值有效 */
    fs_Config_condition_add_static(pConfig, condition_testString2, 2, "node testInt", FsConfig_Condition_equal, "0");
}
// 把配置保存到文件,可使用小雉配置工具打开编辑
// 项目中可把配置发送给客户端
fs_Config_save_to_file_direct(pConfig, "test.cfg");
/* 定义一个xml模拟历史数据导入 */
{
    const char *str = "<testTemplate><testString1>sss1</testString1></testTemplate>"
            "<testTemplate><testString2>ssss2</testString2></testTemplate>"
            "<node><testInt>30</testInt><testFloat>0.5</testFloat></node>";
    FsXml *pXml = fs_Xml_new_from_string__IO(str, NULL);
    fs_Xml_analyzeAll(pXml, (struct FsXml_node*) pXml, NULL);
    FsEbml *pEbml1 = fs_Ebml_new_from_Xml__IO(pXml);
    fs_Xml_delete__OI(pXml, NULL);
    fs_Config_import_onlyData((FsEbml*) pConfig, (struct FsEbml_node*) pConfig, (struct FsEbml_node*) pConfig, (FsEbml*) pEbml1, (struct FsEbml_node*) pEbml1, NULL);
    fs_Ebml_delete__OI(pEbml1, NULL);
}
// 当前pConfig已包含导入的数据,可存盘
fs_Config_save_to_file_direct(pConfig, "test1.cfg");
// 读取历史的配置文件"test1.cfg",按目前在申明导入到pConfig中
{
    FsConfig * const pConfig1 = fs_Config_new_from_file__IO("test1.cfg", NULL);
    fs_Config_import_onlyData((FsEbml*) pConfig, (struct FsEbml_node*) pConfig, (struct FsEbml_node*) pConfig, (FsEbml*) pConfig1, (struct FsEbml_node*) pConfig1, NULL);
    fs_Config_delete__OI(pConfig1, NULL);
}
/* 把pConfig导出为json */
FsObjectBase * const pObjectBase = fs_Config_export_objectBase__IO(pConfig, FsConfig_ExportType_json_export, sizeof (FsObjectBase), 0, NULL);
printf("%s\n", pObjectBase->data);
/* 打印数据为:
 * {
 *     "node":{
 *         "testString":"default1",
 *         "testInt":"30",
 *         "testFloat":"0.500000",
 *         "testBinary":""
 *     },
 *     "testTemplate":[{
 *         "testString1":"sss1",
 *         "testString2":""
 *     },{
 *         "testString1":"default1",
 *         "testString2":"ssss2"
 *     }]
 * }
 */
/* 读取node testInt的值,打印结果为testInt=30 */
printf("testInt=%lld\n", fs_Config_node_integer_get_first(pConfig, pConfig, pConfig, "node testInt", 0, NULL));
/* 读取node testFloat的值,打印结果为testFloat=0.500000 */
printf("testFloat=%lf\n", fs_Config_node_float_get_first(pConfig, pConfig, pConfig, "node testFloat", 0, NULL));
pObjectBase->_delete(pObjectBase);
fs_Config_delete__OI(pConfig, NULL);
return 0;
}

      源码下载地址
      github:https://github.com/feitianzhi/fslib-config
      gitee:fslib-config: 小雉配置--支持向上向下兼容的 配置文件 兼容性 设计 本项目可免费使用,版权归作者所有
      配置工具demo: 小雉配置工具 - 飞天雉&&小雉视频系统文章来源地址https://www.toymoban.com/news/detail-417759.html

到了这里,关于小雉配置--支持向上向下兼容的 配置文件 兼容性 设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Microsoft兼容性遥测是什么?Microsoft兼容性遥测占用高磁盘

    Microsoft兼容性遥测是什么?有用户在检查电脑时发现有个Microsoft兼容性遥测的进程占用较大的磁盘空间,可以禁用该进程来加快系统运行速度吗?下面就来详细看看。 什么是Microsoft兼容性遥测? 此服务在Windows 7,8,10上是合法的.Microsoft兼容性遥测是Windows进程,它存储有关计

    2024年02月04日
    浏览(75)
  • HTML兼容性

    兼容性:页面在不同的浏览器中可能会显示不同。开发人员适配不同浏览器的过程就叫兼容性。 1. 在IE6下,子级的宽度会撑开父级设置好的宽度 提示:盒模型的计算一定要精确,否则IE浏览器可能会显示不同 2. IE6中,元素浮动,如果宽度需要内容撑开,需要给里面的块元素

    2024年02月14日
    浏览(42)
  • 手机兼容性测试

    Android App 兼容性测试: 是一个比较重要的 App 评价指标。 说到测试阶段,兼容性测试主要是对 App 在各类机型上的兼容、适配等情况进行测试。搞清楚这一阶段的测试 重点后,因此,Android App 在进行兼容性测试前,一定要做好其前序测试内容,否则兼容性测试效果将会较差。

    2024年02月08日
    浏览(38)
  • 什么是兼容性测试?

    兼容性测试大家日常都会去做,但是你真的了解兼容性测试吗? 兼容不是别的,而是共同存在或生活的能力。在正常生活中,油和水是不相容的,但牛奶很容易和水结合。 兼容性测试是一种软件测试,用于检查软件是否能够在不同的硬件、操作系统、应用程序、网络环境或

    2024年02月12日
    浏览(55)
  • 共享库的兼容性

    (1)由于Bug的修正、新功能的增加、性能的提升,共享库需要不断的更新版本; (2)共享库的更新可以被分为两类:兼容性更新和不兼容更新; (3)不兼容更新:共享库改变了原有的接口,使用该共享库原有接口的程序可能不能运行或者运行不正常,需要依赖新版本的库

    2024年02月13日
    浏览(37)
  • html常见兼容性问题

    1. png24位的图片在iE6浏览器上出现背景 解决方案:做成PNG8,也可以引用一段脚本处理. 2. 浏览器默认的margin和padding不同 解决方案:加一个全局的 *{margin:0;padding:0;} 来统一。 3. IE6双边距bug:在IE6下,如果对元素设置了浮动,同时又设置了margin-left或margin-right,margin值会加倍。

    2024年02月12日
    浏览(50)
  • uniapp 开发规范(兼容性适配)

    因 uniapp 需同时兼容PC端,移动端,微信小程序端,app端等,建议按以下开发规范开发,可更加有效避开多端不兼容的情况: 此处 class 不要写在 u–form,单独用 view 包裹 u–form 来添加样式 直接在组件上添加样式,会出现某些端不生效的情况,建议统一用样式穿透 + !important实

    2024年01月17日
    浏览(45)
  • Microsoft edge兼容性问题

    连接需要登录界面的无线网络时候,Microsoft edge老是会出现兼容性问题的错误。 这时候设置什么也打不开。 通过网上搜索,我是通过修改注册表的方法成功的。 Win10 Edge兼容性问题打不开|解决浏览器兼容性问题_白云一键重装系统 步骤一:打开运行 ①可以同时按键盘的Win和

    2024年02月10日
    浏览(61)
  • TRichView兼容性问题 Crack

    Markdown导入和导出现在支持存储在Markdown文本中的图像,而不是外部文件。 在TRichView.MarkdownProperties.SaveOptions:rvmdsoInlineImages中添加了一个新选项。 兼容性问题: TRichView.SavePicture有一个新参数:IsBackgroundImage。 对于Apple macOS,Ctrl在默认快捷方式和编辑器中的超链接激活中已更改

    2024年02月04日
    浏览(50)
  • 移动端兼容性问题集锦

    去年主要工作就是混合开发,写app内嵌的h5。在开发期间多多少少遇到些兼容性问题,最近工作比较清闲,整理下方便以后查阅,也希望能帮助到一些同学。 并且本文会持续补充内容,欢迎关注我,另外我会更新一些前端方面的其他一些知识。 问题描述: ios规定日期要以“

    2023年04月08日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包