0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

真刀真枪模块化(2)—图解Service模型

电子设计 作者:电子设计 2020-12-14 22:38 次阅读

作者: GorgonMeducer 傻孩子
首发:裸机思维

【说在前面的话】

在前面一篇文章《真刀真枪模块化(1)——一本糊涂账》中,我们讨论了:

在工程开发中进行模块化的本来目的——为了复用已有的代码,节省当前项目的开发时间;

实际操作过程中遇到的尴尬问题——模块的具体实现原本应该被视作黑盒子,程序员因为各种心理上的原因要阅读代码;

以及

“原则上”的解决方案——严禁程序员在项目开发过程中阅读模块的具体实现代码。

道理说起来简单,真要实际操作起来,一线开发人员往往会直摇头:手中已有的所谓“模块”质量参差不齐、模块的开发者鱼龙混杂、很多模块别说出了问题要找开发方负责维护了,就是原作者是谁恐怕都找不到了——在这种情况下,大谈“禁止开发人员阅读模块的实现代码”,简直就是天方夜谭,颇有几分“何不食肉糜”的傲慢。
——难道模块化本身错了么?实际情况并非如此,这里傻孩子忍不住想“感慨”两句:在追求和实践新的方法(论)的时候,总难免会遇到这样那样的困难,有的困难甚至让整个方案看起来“完全行不通”——在这种时候,如果立即退出来将整个方法全盘否定,就会失去宝贵的前进机会。
在模块化的过程中,要想发挥模块化“复用已有代码”、“降低开发时间”的作用,就必须将模块视作黑盒子;一旦模块被视作黑盒子,实现的质量和后续的可靠维护就成为当前模块是否可用的基石——进一步来说,不靠谱的代码实现和差强人意的接口设计与封装是导致模块化失败的根本原因。
本文将为您介绍一种模块化封装的简单操作方式——由傻孩子根据十多年工程实践经验总结、历经无数商业项目的千锤百炼。通过这一方式构建的模块,我称之为服务(Service),因此,这里所要介绍的模型又被称之为“Service模型”。

【正文】

从具体操作层面来说,所谓Service模型并不复杂。
首先,每一个模块都有一个属于自己的专门的文件夹,文件夹的名称与模块名相同:

其次,每一个模块中都有一个专门的头文件,用于提供给模块的使用者来包含(#include);该头文件的名称必须与模块的名称相同。

需要特别强调和说明的是:

该头文件用于“从模块内部向模块外部”提供使用模块所必须的“最小信息”;

任何人要使用模块,必须且只能包含该头文件;

我们把这类向模块的使用者提供必要信息的头文件称之为接口头文件;

接口头文件遵循“最小信息公开原则”,即,该头文件中只存放用户使用模块最少最少所必须知道的信息。实际操作中,类型定义、宏定义、函数和全局变量声明都应该首先放置在对应的源代码中(或是后面会提到的模块内私有的接口头文件中);当且仅当我们发现用户要使用模块的某一功能必须要用到某一信息时,才“极不情愿”地、“抠门”的、且尽可能将其它能剥离和隐藏的信息剥离开后,放置到接口头文件中。

与接口头文件相对,每一个模块内部都会有一个专门的头文件用于实现对模块的配置:

该头文件用于“从模块外部向模块内部”输入配置信息;

如无特殊说明或安排,该头文件应该固定命名为 app/_cfg.h(没有额外的前缀和后缀);

如无特殊说明或安排,该头文件应该仅包含配置信息,例如:宏定义、类型定义(在极其特殊的情况下,偶尔出现的全局变量或者函数声明);

我们把这类头文件称之为“配置头文件”;

在构建和使用模块的时候,无论是模块的设计者还是模块的使用者,都应该遵循黑盒子原则,在操作上表现为——模块的使用者不应该修改任何位于模块文件夹内部的内容——模块文件夹既是黑盒子的容器,也是黑盒子的边界。
为了遵守这一原则,模块内部的配置头文件实际上是不允许用户去修改的——那么这又如何让用户更改对模块的各个配置选项呢?答案很简单,如下图所示:模块内部的app/_cfg.h 在文件的一开始会首先包含上一级目录的app/_cfg.h。

为了实现这一点,一个模块内部 app/_cfg.h 的固定内容格式为:

//!作为模块的用户,不要修改这里的任何内容

一个模块的接口头文件,其内部格式可能为:

//!作为模块的用户,不要修改这里的任何内容

可以很容易注意到,当使用某一模块时,用户可以很方便的在模块外部定义一个属于自己的 app/_cfg.h 来向模块提供配置信息——而无论如何修改这一文件,都不会破坏黑盒子本身的内容。
再次,一个模块往往拥有一个或多个C源文件,它只需要包含模块的接口头文件,就可以共享一些“对外公开的信息”。

这里有个朋友会问了:根据最小信息公开原则,接口头文件中只包含了一些最小信息,如果模块内的多个C源文件之间需要共享一些非公开的私有信息,该怎么处理呢?
为了解决这一问题,我们一般会引入一个以双下划线为前缀的接口头文件(比如,叫做/_/_common.h),并视其为模块的私有财产。如下图所示,这一头文件是仅供模块内的源代码包含的——无论是模块的接口头文件还是模块的配置头文件都不应该对其进行包含——以防信息泄露:

一个典型的 /_/_common.h 内容如下:

/*!作为模块的用户,不要修改这里的任何内容,理论上也不应该关心这

基于这一规则,模块内一个可能的C源文件内容如下:

//! 作为模块的用户,不要修改这里的任何内容

最后,一个模块内是允许包含其它子模块的,对于这种嵌套情况,仅需要两步骤就可以完成部署:

将子模块拷贝到父模块中,或者按照前述的模块构建规则,在父模块中建立一个子模块;

父模块的接口头文件包含子模块的接口头文件

少数情况下,如果子模块与父模块高度耦合(一般来说就是在父模块中从头开始建立一个新的子模块时会发生这种情况)——比如子模块依赖父模块的 /_/_common.h 中提供的信息,则应该在子模块中也建立一个 /_/_common.h,并仿照 app/_cfg.h 的做法,在头文件的一开始首先向上包含父模块的 /_/_common.h;

如果父模块包含/_/_common.h,而子模块并不需要这一信息,则子模块无需在做任何特殊修改。

对app/_cfg.h来说,由于子模块原本就会自动包含上一级的app/_cfg.h,因此,我们无须做任何特殊操作,子模块就可以透过父模块的app/_cfg.h自动从外界获取配置信息——这就像是一种标准化的水管安装。

以上就是使用Service模型进行模块化的基本规则。是不是很简单?

【后记】

Service模型本身是完全本着简化用户操作的宗旨,以实用性为重中之重,同时也避免一切“反直觉”的设定。
对用户来说,这一模型是非常友好的:

只需要拷贝模块目录就可以完成部署;

只需要在模块的外部额外添加一个app/_cfg.h就可以实现对模块的配置;

所有关于模块的使用信息(使用说明书)都放置在一个唯一的、与模块同名的接口头文件中;且这里包含的信息对用户来说都是可用的(没有无用信息,也没有多余信息);

对模块的开发者来说:

这一模型是高度遵守黑盒子原则的;

用户使用模块,是不需要“用脏手染指”自己宝贵的代码的(无需修改);

对制作 Library 非常友好,只需要保留接口头文件,而将其它所有文件(包括源代码和私有接口头文件)删除并保留一个固化好的app/_cfg.h即可。

模块是非常容易迁移和嵌套的。

当然,这一Service模型也有一个小缺点(可能有些人也对此无法容忍),即,用某些工程管理工具将头文件的包含关系展开时,通常会看到海量的app/_cfg.h(尽管他们内部都使用了模块特有的保护宏进行区别)——对于这一问题,在真刀真枪模块化的后续内容中,将提供一个较为完美的解决方案,这里就先卖个关子——对普通用户来说,现有的Service模型足够了。

审核编辑 黄昊宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 模型
    +关注

    关注

    1

    文章

    3098

    浏览量

    48639
  • Service
    +关注

    关注

    0

    文章

    30

    浏览量

    13762
收藏 人收藏

    评论

    相关推荐

    铭普推出创新模块化储能系统

    铭普公司在通信网络能源领域深耕多年,近日成功推出了一款创新的模块化储能系统,为5G基站节费提供了有力支持。
    的头像 发表于 10-30 17:27 289次阅读

    模块化插座接线方法有哪些

    模块化插座,也称为模块化电源插座或模块化PDU(Power Distribution Unit),是一种可以根据需要灵活配置电源插座和接口的设备。这种设计允许用户根据具体的用电需求,选择不同的
    的头像 发表于 10-18 09:50 219次阅读

    研华工控机的模块化设计,复杂应用场景的灵活解决方案!

    工控机模块化设计是工业自动和嵌入式系统领域的重要趋势。灵活、可扩展的设计,使得用户可以根据实际需求,选择合适的模块进行组合,形成高度定制的工控机产品,从而满足不断变化的市场需求和复
    的头像 发表于 09-07 09:58 264次阅读
    研华工控机的<b class='flag-5'>模块化</b>设计,复杂应用场景的灵活解决方案!

    模块化不间断电源和传统差距,安装位置方面

    模块化UPS(不间断电源)和传统UPS是指不间断电源系统的不同架构和设计。UPS系统具有多种优势,使其成为某些应用的首选。模块化UPS和传统UPS有什么区别?可扩展性模块化UPS:得益于其
    的头像 发表于 06-25 09:34 278次阅读
    <b class='flag-5'>模块化</b>不间断电源和传统差距,安装位置方面

    锂电池是模块化好还是成组好?

    锂电池的模块化和成组是两种不同的设计理念,它们各自有着不同的优势和应用场景。
    的头像 发表于 04-29 15:17 620次阅读

    为什么模块化配线架越来越受欢迎?

    由于现有的布线基础设施无法满足互联网连接设备不断增长的需求,企业必须最大限度地提高网络带宽以满足客户需求,这将导致光纤密度增加和维护困难。模块化配线架以其独特的优势可以为高密度光纤布线设计提
    的头像 发表于 04-07 10:33 330次阅读

    机房升级必备神器:模块化精密空调的五大超能力!

    模块化机房精密空调是一种专门为现代数据中心和机房设计的空调系统,具有以下特点和优势: 灵活性:模块化机房精密空调采用模块化设计,可以根据机房的规模和需求,自由组合不同数量的空调模块
    的头像 发表于 03-19 18:24 1132次阅读
    机房升级必备神器:<b class='flag-5'>模块化</b>精密空调的五大超能力!

    模块化机房:数据中心的未来

    随着数字转型加速,数据中心已成为企业运营的核心。传统的数据中心面临空间利用不足、能源效率低下、扩展性差和维护成本高等问题。模块化机房应运而生,它不仅克服了传统设计的局限,还为数据中心的建设和运营带来了革命性的改变。本文将探讨模块化
    的头像 发表于 03-12 17:26 799次阅读

    什么是模块化机房?

    在这个数据驱动的时代,数据中心的作用变得日益重要。而模块化机房,作为一种创新的数据中心解决方案,正在逐渐改变我们构建和管理这些关键设施的方式。但究竟什么是模块化机房呢?它又为何受到越来越多行业的青睐?在本文中,我们将一探究竟。
    的头像 发表于 03-12 15:05 1307次阅读

    模块化UPS是什么?模块化UPS电源并机的优点

    模块化UPS是什么?模块化UPS电源并机的优点  模块化UPS是一种将UPS电源拆分为多个独立模块的解决方案。每个模块包括一个或多个电池组、
    的头像 发表于 01-10 15:16 1197次阅读

    什么是模块化电池?锂电池模块包装运输要求

    什么是模块化电池?锂电池模块包装运输要求 模块化电池是一种将多个电池单元组合在一起形成一个整体的电池系统。这种构造方式可以使电池在容量、电压、能量密度等方面得到有效的提升,同时也可以提高电池的安全性
    的头像 发表于 01-10 11:42 1135次阅读

    什么是模块化锂电UPS?模块化UPS支持锂电池吗?

    什么是模块化锂电UPS?模块化UPS支持锂电池吗? 模块化锂电UPS是一种基于锂电池技术的不间断电源系统(UPS),它的主要特点是可以根据需求进行模块化扩展和灵活配置。
    的头像 发表于 01-09 15:51 784次阅读

    LumiDL TM模块化照明器介绍

    今天我们为大家介绍一下LumiDL TM模块化照明器。
    的头像 发表于 01-08 11:11 641次阅读
    LumiDL TM<b class='flag-5'>模块化</b>照明器介绍

    太阳能应用的模块化电池系统

    电子发烧友网站提供《太阳能应用的模块化电池系统.pdf》资料免费下载
    发表于 11-16 15:31 0次下载
    太阳能应用的<b class='flag-5'>模块化</b>电池系统

    不同尺度子网络的模块化神经网络同步转换

    考虑到模块化网络中不同位置的时间延迟可能具有不同作用,我们探讨子网络之间以及子网络内部的时间延迟对模块化网络同步的影响。我们发现,当子网络内同步良好时,两个子网络内部时间延迟增加会诱发其自身出现多个同步转换。
    的头像 发表于 11-08 14:47 446次阅读
    不同尺度子网络的<b class='flag-5'>模块化</b>神经网络同步转换