[架构之路-216]- 架构 - 概念架构 - 模块(Module)、组件(Component)、包(Package)、对象、函数的区别

news2024/12/23 0:24:37

前言:

在软件架构中,一个重要的任务就是切分系统,而切分系统进程涉及到一个基本的概念,如模块(Module)、组件(Component)、包(Package)、对象,本文澄清他们的区别。

组件(Component)和模块(Module)是一对容易混淆的名词,也常常被用来相互替换。

两者是否有差异往往取决专业背景、所在领域、以及视角。

从设计上来看,组件强调复用,模块强调职责(内聚、分离),或者说组件是达到可复用要求的模块。

模块、组件和对象这三个名词,是软件开发中非常常见的说法。在很多软件平台、库、框架中,都使用这三个名词作为描述其复杂结构的单元结构。模块、组件、对象三者虽然有相似的含义,但是,也有非常大的差别,本文探究这三个概念的异同目的,并非仅仅是规范这些用语,而是希望能对复杂软件的解构单位,作一次较完整的思考。

备注:

在有些场合和书籍中,上述概念的关系是:函数 --》模块--》组件--》包

1. 追溯历史

孙子兵法云:“制众如治寡,分而治之”。意思是:处理数量庞大而复杂的事物,其实和处理简单、单一的事物一样简单,关键是要把处理的目标分解开。

软件系统的发展过程里,也对分解有很多不同的尝试。

1.1 函数的出现

早期结构化编程流行的阶段,软件是一个被层层分解的函数,每个函数都被划分成更多,具备平行含义的子函数。整个程序的结构就好像一本分类学书籍,由一个主题目main(),划分成非常多的子标题,子标题下面又分为更小的标题,形成一个树状的结构,如下图所示:

1.2 单函数模块的出现

如果我们需要对这样一个程序的某部分代码重用,也就是说抽取其中一部分代码,放到其他程序里面,那么,一般来说都要以“函数”为包装形式,否则,拷贝整段代码的缺点是显而易见的。

函数用作来重用代码,天然的有其接口形式:参数与返回值(或者是输入参数与输出参数)。因此,一个函数,就能成为一个封闭的代码块,具备固定的输入和输出接口,多个功能相关的函数,组合在一起,我们称之为模块

1.3 工具模块的出现

然而,当我们在编写“函数模块”的时候,往往会发现,针对同一块数据,往往需要多个函数来一起操作。比如我们操作文件,针对特定的一个文件,我们需要打开、添加、删除、关闭这个文件。如果每个操作都是一个函数,那么我们的输出参数往往都需要一个代表文件的指针;而这个指针,又往往是其他函数的输入参数。——这种做法,实际上是破坏了模块的重用性,因为针对“模块”这个概念,我们设想的是,能简单使用一些输入参数,就能获得操作结果,而不希望还要关心输入参数的状态,以及维护输出参数的状态。由于我们编写的大多数商业系统中,都是针对一些数据进行操作,而不仅仅是进行某些数据的运算,所以数据状态反而成了程序的核心,各种所谓的“模块”,都是为了修改、操作某些特定数据的工具而已。是一组函数的组合。

也许有人会说,这样的工具模块不也是挺好的吗?当然,从代码重用的角度来说,模块和工具都可以很方便的被重用在需要的地方。但是,我们希望被重用的代码,是能够比较简单的去使用的,如果使用“工具型函数”,需要用户去小心的维护一个复杂的数据模型,那么就达不到“简单”的重用代码的目的了。举个例子,如果我们有10个工具函数,都是操作同一个数据指针的,而这些函数的调用还是有一定的调用顺序或其他逻辑约束的,那么我们在使用的时候,就要认字仔细的查看例程,彻底搞明白这10个函数的关系,然后按设计者的思路小心翼翼的去使用。否则,如果只是看了下函数手册就用起来,很可能就会碰到诸如“未定义”的结果这类奇怪的错误。

1.4 对象的出现

显然,我们对于“模块”的追求,无法简单的用函数这个工具来实现,因此人们想到,我们能不能把数据和函数组合起来,这样使用的时候,就不需要在使用的时候去维护复杂的状态。——因此诞生了面向对象。这里的“对象”,指的就是把数据,和操作这些数据函数,根据内在逻辑封装起来的单位。由于有了这种封装,一个对象除了代表业务数据状态以外,还附带了一系列的“方法”,这些“方法函数”是可以随时随意的调用,而用来操作对象的。

虽然这些“方法函数”同样还是可以设置“输入参数”和“输出参数”,但是我们完全可以把方法函数所依附的对象(this对象),作为自由操作的输入或输出参数。我们在编写方法函数的时候,就可以有意识的去管理所依赖的数据状态——this对象,这样任何一个方法函数,都可以明确而唯一的操作this的内容,而无需用户去操心。

举个例子,如果我们用面向对象的类库去操作文件,我们只需要创建一个File对象,就可以随意的删除、更新、修改这个对象的内容。如果这个对象对应的文件没有打开,或者不存在,那么File对象本身会有一个状态值做记录,那些删除、更新的方法就可以先判断一下这个状态值,从而返回“错误”提示。这样就可以避免用户去按照某些逻辑约束使用各个方法,极大的降低了对象作为“模块”的学习难度。

1.5 组件的出现

对象这个概念,对于那些希望把数据+操作构建成模块的情况,是非常合适的。但是,他也有一些缺点。其中有一个非常典型,就是对象模型是一个编程语言的概念,本质上一个对象只是内存中的一堆数据。然而我们要使用的模块,往往不止是内存中的一堆数字就能解决问题的。比如我们需要管理数据库中的一个表,或者操作一个GUI的按钮,又或者控制一个游戏里面的动画角色……这些都不止用内存中的“属性”能满足。

这个时候,人们依托IDE工具,把许多需要复用的复杂数据,和对象模型关联起来,封装成一个个可以根据预先约束的用法去使用的模块,这就是组件了。组件一般会比对象的约束要多,因为每一类组件,都有明确的使用接口,以便能“组合”到某个框架里面。比如JavaBean规范规定,所有这类的组件,必须要以getter/setter的形式对外提供属性的读写。又比如Flex规范中,组件甚至可以仅仅用XML来描述,而不必要是某种程序代码。

总体来说,所谓组件,是在某套使用规范下,特别构建的软件模块。这种模块很多依托对象模型,有所谓“属性”和“方法”。但是这些属性和方法,为了能提供更直观方便的使用接口,一般会有所约束。一旦满足这些约束,开发者重用这种模块的时候,甚至是不需要用编程语言来调用这些“属性”、“方法”。所以组件和对象的差别,往往是在于其约束方面。很多组件都要求对象从某个基类派生,或者要有一个主动注册和校验的程序,才能从对象编程组件。但是反过来一般组件都提供某种编程语言下的对象模型,让用户可以对其编写代码。

因此,我们可以看出,模块、对象、组件之间是有一定的关系,但并不完全等同。一般来说,我们喜欢把任何可重用的代码都成为模块,我们希望模块是简单的、仅仅通过输入输出就能控制的重用代码,所以其含义是最广泛而通用的。可惜现实中能很简单使用的模块并不多,为了能处理复杂的问题,人们开发了很多编程的工具,其中一些为了解决特定问题,比如数据库、GUI、游戏,都强化了一些模块的使用方法,让可重用的代码,能更简单的投入使用,而这些易用性上的好处,都需要付出遵守一定的规范的代价。

这些能在特定问题解决框架下运行的模块,就成为了组件。虽然模块和组件本身都不需要采用面向对象的模型,但是面向对象作为编程上的一个重要概念,能帮助使用者理解和操作模块或者组件,并且因为其封装管理数据状态的特征,能降低编程上的复杂程度,更容易对业务领域建模,所以很多模块和组件,背后都采用了面向对象的概念来打造其编程接口和表现形式。

应用(Application):

应用系统,由多个Module组成,用方框表示。

模块(Module):

中文为模块。它的核心意义是分离职责,属于代码级模块化的产出。

模块是从代码逻辑角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一。

本身是一组具有一定内聚性代码的组合职责明确。对外的接口可以是松散的,也可以是集中的。

SEI的定义如下:

An implementation unit of software that provides a coherent set of responsibilities.

它以问题分解的形式,来解决软件设计问题。它更强调一个内聚的概念,形式上可以是Java中的包,也可以是一个源代码目录。

一个Module是由一组Component构成,用正方体表示。

组件(Component):

中文称为组件,或者构件。

组件是程序设计角度抽象出的可复用的单元,而且大多数时候是站在技术视角做的抽象。

一个模块可能有多个组件,一个组件也可能被多个模块使用。

组件可以是一个SDK、一个工具包、一个方法。

组件使用非常比较广泛,它的核心意义在于复用,相对模块,对于依赖性有更高的要求。

表示一个可以独立提供某方面功能的物件,用UML的组件图表示。

包(Package):

应用程序、模块、组织,都是功能的组织形式,

Package是一种目标系统文件的组织形式,和粒度不是一个维度的,也就是说,一个Component可以包含多个Package,一个Package也可以包含多个Component

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/687179.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

亚马逊云科技以用户为中心,持续丰富安全服务和解决方案

AI加持安全,自动化运营成未来趋势 亚马逊云科技始终在云安全领域不断创新探索、深耕发力,随着全球技术的发展而持续迭代安全能力。 当下,以ChatGPT为代表的AIGC成为最出圈的热点,大量的科技巨头纷纷涌入AI赛道,投入了…

16. WebGPU 数据内存布局

在 WebGPU 中,提供给它的几乎所有数据都需要在内存中设定布局,以匹配在着色器中定义的内容。这与 JavaScript 和 TypeScript 形成鲜明对比,后者很少出现内存布局问题。 在 WGSL 中,当编写着色器时,通常定义 struct 。…

Redis集群详解

目录 一、前言二、Redis 集群方案应该怎么做?都有哪些方案?三、twemproxy四、分而治之-codis1、codis简介2、Codis 分片原理3、不同的 Codis 实例之间槽位关系如何同步?4、假如Redis扩容,如何调整槽位的?5、codis优缺点…

巧用 overflow-scroll 实现丝滑轮播图

前言: 近期我在项目中就接到了一个完成轮播图组件的需求。最开始我也像大家一样,直接选择使用了知名的开源项目 “Swiper”,但是后来发现它在移动端项目中某些测试环境下会白屏一段时间。无论如何调试都不能修复这个问题,于是就自己上手写了个…

Java智慧工厂UWB高精度人员定位管理系统源码

一、系统概述: 智慧工厂高精度定位管理系统源码,采用UWB定位技术,通过部署UWB定位设备实现人、车、物精确定位,打造可寻、可视、可防、可控的一体化管控平台。UWB定位系统具有容量大、稳定性强、精度高、安装便捷、易维护、操作简…

pebblely无需代码连接集简云数据表的方法

1 使用场景 当电商UI接到一个设计产品图的需求时,按照常规的工作安排,从对接需求到最后完成效果图最短时间都要在5天左右,如果遇到高要求的客户,后期还需要在电脑上进一步调整细节,一张成片起码要花上数小时时间去完成…

LabVIEW开发压电陶瓷特性测试系统

LabVIEW开发压电陶瓷特性测试系统 目前,随着科学技术的飞速发展,各个领域都需要纳米级的精密定位系统。而压电定位系统是迄今为止已经得到认可的微纳定位系统。该系统主要由压电驱动系统、位移测量传感器和控制系统组成。其中,整个压电驱动系…

oracle 使用sql语句实现交换一个表中两条记录的某个字段的内容

不要太忙了 好好珍惜眼下 的真爱 (马晓静sorry~) 表 test --------------- id | i_order --------------- 1 | 22 2 | 23 --------------- 转换后结果为: --------------- id | i_order --------------- 1 | 23 2 | …

【云原生丶Docker】Docker镜像常用命令大全

镜像是Docker中最为核心也是最具创造性的概念!在理解Docker的核心概念文章中,我们理解了镜像的含义,下面让我们一起操作一些镜像,包括拉取、推送镜像等操作。 1、镜像支持哪些命令 通过 docker image help 查看 Docker 支持的镜像…

解决nacos频繁输出get changegroupkeys日志

# 1、根据心跳日志,定位日志输出的包名 c.a.n.client.config.impl.ClientWorker : get changedGroupKeys:[]# 2、在 IDEA 中搜索 ClientWorker 所在的包路径 package com.alibaba.nacos.client.config.impl;# 3、在任意格式的配置文件中将该包路径的日志设置为…

Unity 工具 之 Azure OpenAI 功能接入到Unity 中的简单整理

Unity 工具 之 Azure OpenAI 功能接入到Unity 中的简单整理 目录 Unity 工具 之 Azure OpenAI 功能接入到Unity 中的简单整理 一、简单介绍 二、实现原理 三、注意实现 四、简单实现步骤 五、关键代码 六、附加 创建新的 .NET Core ,获取 Azure.AI.OpenAI d…

公司个人年终工作总结【10篇】

公司个人年终工作总结1 20__年即将过去,在公司领导的悉心关怀下和同事们的帮助指导下,结合我自身的努力,在工作、学习等各方面都取得了长足的进步,尤其是在保险理赔专业知识和技能培养方面的成熟,使我成为一名合格的车…

Linux_查看硬盘占用情况

一、查看是什么占用了硬盘空间 df -h 这个命令查看的是显示目前在 Linux 系统上的所有文件系统磁盘使用情况,并根据大小适当显示(-h 参数代表以可读的方式展示文件的大小)。 一下为加 -h 和不加 -h 的结果 不加 -h 加 -h Filesystem&…

探秘安卓广播:揭秘Android广播机制的神奇之处

壹 广播机制 Android中的广播(Broadcast)机制用于进程/线程间通信,该机制使用了观察者模式。观察者模式是一种软件设计模式,该模式是基于消息的发布/订阅事件模型,该模型中的消息发布者是广播机制中的广播发送者,消息订阅者是广播…

ajax原理是什么?如何实现?

一、是什么 AJAX全称(Async Javascript and XML) 即异步的JavaScript 和XML,是一种创建交互式网页应用的网页开发技术,可以在不重新加载整个网页的情况下,与服务器交换数据,并且更新部分网页 Ajax的原理简单来说通过XmlHttpReq…

算法——查找表

查找,根据一个值查找另一个值,value值可以是容器,结构,这样可查找的元素就更多; 哈希冲突: 主关键字:可以唯一的标识一个记录的关键字,如准考证号; 此关键词&#xff…

RFID微图柜的操作流程以及功能介绍

微型图书馆智能书柜是一种基于 RFID 技术的图书自助借阅延伸服务的终端设备,可实现 24 小时无人看守的共享的智能化设备,可自助借还书、自动数据记录分析、自助提醒等一体化管理服务功能。 智能书柜的操作流程 借书:在操作页面上选择“借书…

【好书精读】网络是怎样连接的 —— 信号在网线和集线器中传输

( 该图由我使用 AI 绘制 ) 目录 每个包都是独立传输的 防止网线中的信号衰减很重要 “双绞”是为了抑制噪声 集线器将信号发往所有线路 每个包都是独立传输的 从计算机发送出来的网络包会通过集线器 、 路由器等设备被转发 , 最 终到达…

解决 CentOS/Alma 安装 libpcap-devel 报错:No match for argument: libpcap-devel

环境:Alma 8.5、Centos 7.x 解决方案 Linux 安装软件的时候,需要 libpcap-devel 这个组件,执行命令:yum install libpcap-devel ,然后报错如下: Last metadata expiration check: 0:05:24 ago on Mon 12…

5.3 Linux目录配置

5.3.1 Linux目录配置的依据--FHS 根据FHS的标准文件指出,他们的主要目的是希望让使用者可以了解到已安装软件通常放置于那个目录下, 所以他们希望独立的软件开发商、操作系统制作者、以及想要维护系统的使用者,都能够遵循FHS的标准。 也就是…