前端:组件、插件、模块、子应用、库、框架等区别

简介: 前端:组件、插件、模块、子应用、库、框架等区别

组件、插件、模块、子应用、库、框架等概念辨析

网上有许多讲组件化、模块化等概念的文章,但大家一般都是将这两个概念混为一谈的,并没有加以区分。而且实际上许多人对于组件、插件、模块、子应用等概念的区别也不甚明了,甚至于许多博客文章专门解说这几个概念都有些谬误。

之前已经写了一篇文章专门对组件和模块两个概念进行辨析,现在我们对于更多的概念在更高的层次上进行辨析。

想分清这几个概念我觉得结合一下软件的渐进式开发场景更容易理解。但是下面的篇幅会比较长,所以按惯例还是先说结论,不耐烦的同学可以先看:

1.概念区别

  • 组件:代码重用,功能相对单一或者独立,无统一接口。组件化开发的成果是基础库和公共组件。
  • 插件:近乎组件,有统一接口
  • 模块:高内聚,松耦合,功能相对复杂,有多个统一接口。模块化开发的基础是框架。
  • 子系统:高于模块,需要生命周期管理。子系统开发的基础是容器。

1.1.组件和插件

插件的概念比较形象,一般存在一个“插拔”过程,所以要求可插拔的插件有一个相同的接口(这里所说的接口只是概念上的接口,即调用方法及参数等)。而组件是不存在这个相同接口的。

拿我们最常见的网络请求功能举例,无论哪种开发语言,github上可能都有多种网络请求组件,那么对于一个项目而言,从一个网络组件ComponentA切换为另一个网络组件ComponentB是基本无法做到调用方法不改动的。

而如果把网络请求组件插件化,即在组件外层抽象一层统一化的调用接口NetworkInterface,然后将当前使用网络请求组件ComponentA包装成实现该接口的网络请求插件PluginA。那么如果以后需要将使用的ComponentA切换为ComponentB,那么只需要将ComponentB包装成PluginB并插入到应用中即可。实际调用时,业务代码还是调用NetworkInterface,不用做任何修改。

从上面这个例子我们可以看出,插件和组件的实质区别就在于通过统一接口隔绝业务代码对于组件的直接依赖,这也是我们常听到的所谓的“项目开发时应该把第三方组件封装一下再用”。

1.2.组件和模块

两者的实质区别在于:组件化开发是纵向分层,模块化开发是横向分块。

所以,模块化并没有要求一定组件化,就是说进行模块化拆分时你可以完全不考虑代码重用,只是把同一业务的代码做内聚整合成不同的模块。只不过这样得到的成果相对简单,我们一般不会这样而已。

组件化就比如项目中公共的alert框,它的出现其实是基于代码复用的目的,所以我们把它封装,并给多个地方使用。而模块化就比如一个资讯列表界面,它本身可能只在一个地方使用,没有复用的需求,但我们也要把它封装成模块,这是高内聚的要求,我们不应该把资讯相关的代码在项目中放得到处都是。

但像这样的简单模块只是轻模块,统一接口较少。而统一定义的接口越多,其实和主应用的耦合就越高,也便是重模块。

而路由就是解决高耦合问题的,不过耦合问题不是模块化开发的需求,只不过我们一般都会在这个时间考虑这一事情而已,就像我们不会只做模块化开发同时不做组件化开发一样。

1.3.模块和子应用

模块和子应用的区别与组件和插件的区别有点像,都在于一个统一接口。

子应用我们不常提,但其实并不少见,像微信小程序,钉钉中的第三方应用还有企业OA应用中集成的周边功能模块都应该属于子应用的概念。

对于模块而言,它暴露给外部调用的接口一般很少,最常见的就是上面提到的路由规则,相当于可以让外部通过路由规则展示它。而子应用需要的就不只是一个展示接口,它可能需要动态的控制子应用的生命周期,以及其他功能上的信息交互(比如,账户信息的同步),甚至于要做到类似插件那样的插拔效果。

所以子应用必然是接口化的,而模块则没有硬性的要求。

1.4.库和框架

除了上面这四种概念,还有两个是我们开发中常遇到的:库和框架。

库,或者基础库,概念上偏近于各种工具积累成的集合,是软件代码的层面是分层的概念,所以对应组件化。基础库甚至可以看做是一个大的组件。

而框架顾名思义是结构化的,是相对整体的一个概念,所以应用于模块化,甚至是子应用化。

比如在iOS中,RAC是一个库,而基于此的一套MVVM的具体实现成果(单页面的文件结构,多页面的交互等等)才叫框架。因为框架本身就有架构思想在里面。

2.渐进式辨析

上面讲了一下几个概念的区别,当然这几个概念在服务端开发和客户端开发领域可能有些微差别,我们就不深究了。想要更深入的了解这些概念的区别,我准备拿一个渐进式开发移动端项目的例子进行辨析。

首先我们定义一个虚拟的产品——一款知识类应用,包含常见的资讯、问答、学院、直播等功能。

接下来我们从设计的角度逐步拆分这个产品。

0.原始态

如果开发时没有考虑任何组件化、模块化开发,那么此应用的所有功能都是堆积在一起的,总结起来就是代码特点就是高耦合,低内聚,无重用。

面对这样的一堆代码,技术经理可能要让你做一下代码重构,这就是你下一步的工作。

1.组件

那么你进行代码重构的第一步是什么呢?

答:将工程中重复的代码合并成为一份,也就是重用。

如果让我们来看组件化开发的定义,它的着重点就是代码重用。那这一步最后的结果就是提炼出一个个组件给不同的功能使用。

这里我们可以看一下其中的依赖关系:具体功能依赖提炼出来的组件,组件本身之间可能也有依赖关系,但一般不多。所以我们总结组件化开发的原则就是高重用,低耦合。当然这只是相对而言。

基于这样的认识,我们甚至于可以把资讯、问答、学院、直播等功能封装成组件,只不过这些组件比较大,依赖可能多些,不过本质上没有多少区别。

就在你进行重构的过程中,这时需求来了:运营人员要求首页顶部的九宫格样式工具栏可动态配置,通过服务端数据修改显示功能,并调用对应的功能页面。

2.插件

代码重构从来不是超然物外的,在进行过程中接到新需求也是常有的事情。那么,对于这样一个需求,应该怎么考虑呢?

这个动态化需求很普遍,只不过这里有一个隐性要求——既然需求中要求功能动态配置,那么调用功能的地方就不知道功能的具体实现。

所以最终的方案中被调用功能必须有统一接口。我们这里说的接口只是编程领域的抽象概念,并非是指具体语言的interface或者protocol。

而有了这一统一接口,其配置功能其实就是“插拔”过程了。这样的成果实质上已经是插件了。

插件可以解释成可插拔式组件,它的核心就是不同功能实现提供统一接口。

项目中插件化的例子其实也不少,再举一个例子:比如资讯和问答功能使用的弹框样式不同,但是在两个功能内部其弹框样式是一致的。

面对这样的问题,你在重构时可能会简单的封装出两个组件AlertA和AlertB,分别给两个功能使用。这样确实很便捷,而且适合当下的场景,但是从设计或者长远发展的角度上来考虑,如果资讯里面弹框样式需要换成和问答一样,甚至其他样式,那么基于现有的方法,你就需要修改资讯功能中所有调用弹框的地方。

所以插件化是解决这个问题的好办法:定义AlertInterface接口给具体业务功能使用,并实现AlertPluginA、AlertPluginB,在外面给不同的功能指定不能的插件即可。

3.模块

这时候项目的组件化拆分完成,技术经理说以后不同的模块会交由不同的人来维护,各人维护各自负责的代码。

这个需求初看上去只是项目管理上的需求,但实际执行时若资讯、问答、学院、直播分别由四个人维护,那么他们虽然大部分代码是相互隔离的,但仍然会有相当一部分代码耦合在一起,有时候会同时修改同一个代码文件。

这时候要做的自然就是模块化。

为什么是模块化呢?按照模块的定义,它是以关注点进行划分的,而关注点说到底就是功能,也就是说根据我们上面的例子,资讯、问答、学院、直播可以分成不同的模块。

我们最开始定义这个虚拟产品的时候说,它有三个特点——高耦合、低内聚、无重用。而第一点组件化开发主要是解决了重用问题,提升了部分内聚,而耦合问题则没有涉及。

所以说我们上面可以将这个产品在逻辑上划分为资讯、问答、学院、直播四个模块,但在代码层面上它们却不是四个模块,因为它们的代码都是混杂在一起的。比如产品首页,可能推荐了部分资讯、显示了热门问答、推送了目前的直播,而这些功能的代码则是写在一起的;再比如程序启动的时候,这四个模块都需要初始化一些数据,而初始化数据的代码也是写在一起的。

而模块化开发就是为了解决这一问题,即提高内聚,将分属同一模块代码放到一起;降低耦合,将不同模块间的耦合程度弱化。

高内聚是这一步的目标。但现状是有许多地方会用到多个模块,比如启动的时候会调用四个模块,首页会展示三个模块的界面。如果要高内聚,那么必然需要这些模块为不同的场景提供相同的方法,这就是说所有模块要实现同一套多个接口。

而低耦合其实并非是模块化开发的要求,其实更多时候是基于产品上的动态化要求,所以最常见的解决方案就是路由机制。

讲到这里,我们可以看到模块化和组件化的区别就已经很明显了。

对于一般应用而言,代码设计优化到这一步就很好了,无论是代码可读性、可维护性、工作协作效率都得到了保障。不过为了讲到我们上面所说的所有概念,我们不妨皮一下,给自己提点需求:

产品经理想把学院模块单独提出来做一个APP,但是因为技术经理反映开发资源有限,不能给这个APP配备独立的开发人员,所以最终的结果是这个APP的功能和原应用中的学院模块使用同一套代码,且功能相同。

4.子应用

对于开发人员来说,这也不能算多困难的需求,只需要再创建一个新工程,将学院模块代码引用过来并显示即可。

这个方案简单直接,即便后面再把直播分离出单独APP我也可以这样来做。

但是,有没有觉得这个方案和我们之前提到的Alert的例子有些神似,在这个方案中,新的工程必然直接耦合具体的模块代码,你需要在里面编写很多初始化代码。而这样的代码在单独的APP中和原APP中是相当类似的。

按照《重构》一书中的提法,这是明显的坏味道,我们应该在工程和模块代码之间抽象出一层接口,使两者解除直接耦合,这样我们甚至可以做到只需要配置就可以将一个模块变成一个新的APP。

(或许在这个例子中,有些过度设计了,但是原谅我举不出更合情理的例子TAT)

上面方案的成果,实际上就把学院模块编程了学院子应用,而这个子应用被原APP和新的独立APP所使用。

在概念上,子应用比模块的范围更大,子应用要求能在主应用里运行,也要求必要时可以自己运行,那么就必然要求子应用要提供生命周期接口,和主应用必要时保持一致。

其实在上面一步的模块化开发中,有的时候也会有生命周期接口的要求,只不过并非强制,而子应用的设计中则是必须要考虑的。

3.总结

到此,我们就把组件、插件、模块、子应用四个不同程度的设计概念异同讲完了,希望读者能有所得。文章中若有其他不足之处,恳请不吝赐教。







目录
相关文章
|
2天前
|
SpringCloudAlibaba JavaScript 前端开发
谷粒商城笔记+踩坑(2)——分布式组件、前端基础,nacos+feign+gateway+ES6+vue脚手架
分布式组件、nacos注册配置中心、openfegin远程调用、网关gateway、ES6脚本语言规范、vue、elementUI
谷粒商城笔记+踩坑(2)——分布式组件、前端基础,nacos+feign+gateway+ES6+vue脚手架
|
15天前
|
前端开发 开发者
在前端开发中,webpack 作为一个强大的模块打包工具,为我们提供了丰富的功能和扩展性
【9月更文挑战第1天】在前端开发中,Webpack 作为强大的模块打包工具,提供了丰富的功能和扩展性。本文重点介绍 DefinePlugin 插件,详细探讨其原理、功能及实际应用。DefinePlugin 可在编译过程中动态定义全局变量,适用于环境变量配置、动态加载资源、接口地址配置等场景,有助于提升代码质量和开发效率。通过具体配置示例和注意事项,帮助开发者更好地利用此插件优化项目。
44 13
|
8天前
|
Web App开发 前端开发 JavaScript
Web前端项目的跨平台桌面客户端打包方案之——CEF框架
Chromium Embedded Framework (CEF) 是一个基于 Google Chromium 项目的开源 Web 浏览器控件,旨在为第三方应用提供嵌入式浏览器支持。CEF 隔离了底层 Chromium 和 Blink 的复杂性,提供了稳定的产品级 API。它支持 Windows、Linux 和 Mac 平台,不仅限于 C/C++ 接口,还支持多种语言。CEF 功能强大,性能优异,广泛应用于桌面端开发,如 QQ、微信、网易云音乐等。CEF 开源且采用 BSD 授权,商业友好,装机量已超 1 亿。此外,GitHub 项目 CefDetector 可帮助检测电脑中使用 CEF
46 3
|
15天前
|
Android开发 iOS开发 C#
Xamarin:用C#打造跨平台移动应用的终极利器——从零开始构建你的第一个iOS与Android通用App,体验前所未有的高效与便捷开发之旅
【8月更文挑战第31天】Xamarin 是一个强大的框架,允许开发者使用单一的 C# 代码库构建高性能的原生移动应用,支持 iOS、Android 和 Windows 平台。作为微软的一部分,Xamarin 充分利用了 .NET 框架的强大功能,提供了丰富的 API 和工具集,简化了跨平台移动应用开发。本文通过一个简单的示例应用介绍了如何使用 Xamarin.Forms 快速创建跨平台应用,包括设置开发环境、定义用户界面和实现按钮点击事件处理逻辑。这个示例展示了 Xamarin.Forms 的基本功能,帮助开发者提高开发效率并实现一致的用户体验。
34 0
|
15天前
|
开发者 存储 API
Xamarin 开发者的社区资源概览:从官方文档到GitHub示例,全面探索提升开发技能与解决问题的多元化渠道与实用工具
【8月更文挑战第31天】Xamarin 开发者社区资源概览旨在提升开发效率与解决问题,涵盖官方文档、社区论坛、GitHub 项目等。官方文档详尽,涵盖 Xamarin.Forms 使用、性能优化等;社区论坛供交流心得;GitHub 提供示例代码。此外,第三方博客、视频教程及 Xamarin University 等资源也丰富多样,适合各阶段开发者学习与提升。通过综合利用这些资源,开发者可不断进步,应对技术挑战。
30 0
|
15天前
|
前端开发 Java UED
JSF 面向组件开发究竟藏着何种奥秘?带你探寻可复用 UI 组件设计的神秘之路
【8月更文挑战第31天】在现代软件开发中,高效与可维护性至关重要。JavaServer Faces(JSF)框架通过其面向组件的开发模式,提供了构建复杂用户界面的强大工具,特别适用于设计可复用的 UI 组件。通过合理设计组件的功能与外观,可以显著提高开发效率并降低维护成本。本文以一个具体的 `MessageComponent` 示例展示了如何创建可复用的 JSF 组件,并介绍了如何在 JSF 页面中使用这些组件。结合其他技术如 PrimeFaces 和 Bootstrap,可以进一步丰富组件库,提升用户体验。
26 0
|
15天前
|
开发者 安全 UED
JSF事件监听器:解锁动态界面的秘密武器,你真的知道如何驾驭它吗?
【8月更文挑战第31天】在构建动态用户界面时,事件监听器是实现组件间通信和响应用户操作的关键机制。JavaServer Faces (JSF) 提供了完整的事件模型,通过自定义事件监听器扩展组件行为。本文详细介绍如何在 JSF 应用中创建和使用事件监听器,提升应用的交互性和响应能力。
13 0
|
15天前
|
开发者 自然语言处理 存储
语言不再是壁垒:掌握 JSF 国际化技巧,轻松构建多语言支持的 Web 应用
【8月更文挑战第31天】JavaServer Faces (JSF) 框架提供了强大的国际化 (I18N) 和本地化 (L10N) 支持,使开发者能轻松添加多语言功能。本文通过具体案例展示如何在 JSF 应用中实现多语言支持,包括创建项目、配置语言资源文件 (`messages_xx.properties`)、设置 `web.xml`、编写 Managed Bean (`LanguageBean`) 处理语言选择,以及使用 Facelets 页面 (`index.xhtml`) 显示多语言消息。通过这些步骤,你将学会如何配置 JSF 环境、编写语言资源文件,并实现动态语言切换。
21 0
|
15天前
|
iOS开发 Android开发 MacOS
从零到全能开发者:解锁Uno Platform,一键跨越多平台应用开发的神奇之旅,让你的代码飞遍Windows、iOS、Android、macOS及Web,技术小白也能秒变跨平台大神!
【8月更文挑战第31天】从零开始,踏上使用Uno Platform开发跨平台应用的旅程。只需编写一次代码,即可轻松部署到Windows、iOS、macOS、Android及Web(通过WASM)等多个平台。Uno Platform为.NET生态带来前所未有的灵活性和效率,简化跨平台开发。首先确保安装了Visual Studio或VS Code及.NET SDK,然后选择合适的项目模板创建新项目。项目结构类似传统.NET MAUI或WPF项目,包含核心NuGet包。通过简单的按钮示例,你可以快速上手并构建应用。Uno Platform让你的技术探索之旅充满无限可能。
22 0
|
15天前
|
前端开发 JavaScript 开发者
JSF与WebSockets,打造实时通信魔法!让你的Web应用秒变聊天室,用户体验飞升!
【8月更文挑战第31天】在现代Web应用开发中,实时通信对于提升用户体验至关重要。本文探讨了如何在主要面向Web应用开发的JSF(JavaServer Faces)框架中引入WebSockets支持,以实现客户端与服务器之间的全双工通信。通过具体示例展示了在JSF应用中实现WebSockets的基本步骤:添加依赖、创建服务器端点以及在前端页面中嵌入JavaScript客户端代码。尽管这一过程中可能会遇到一些挑战,如复杂代码编写和额外配置需求,但借助AWS等云服务平台,开发者仍能高效地完成部署和管理工作,从而增强Web应用的实时通信能力。
22 0