组件化

转自:

组件化开发和模块化开发概念辨析

https://blog.csdn.net/blog_jihq/article/details/79191008

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

https://blog.csdn.net/blog_jihq/article/details/80669616

组件化开发和模块化开发概念辨析

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

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

概念区别
对比
类别 目的 特点 接口 成果 架构定位
组件 重用、解耦 高重用、松耦合 无统一接口 基础库、基础组件 纵向分层
模块 隔离/封装 高内聚、松耦合 统一接口 业务框架、业务模块 横向分块
说明
组件:最初的目的是代码重用,功能相对单一或者独立。在整个系统的代码层次上位于最底层,被其他代码所依赖,所以说组件化是纵向分层。
模块:最初的目的是将同一类型的代码整合在一起,所以模块的功能相对复杂,但都同属于一个业务。不同模块之间也会存在依赖关系,但大部分都是业务性的互相跳转,从地位上来说它们都是平级的。
因为从代码组织层面上来区分,组件化开发是纵向分层,模块化开发是横向分块,所以模块化并没有要求一定组件化。也就是说你可以只做模块化开发,而不做组件化开发。那这样的结果是什么样的呢?就是说你的代码完全不考虑代码重用,只是把相同业务的代码做内聚整合,不同模块之间还是存在大量的重复代码。这样的成果也算是做到了模块化,只不过我们一般不会这样而已。

和组件模块近似的一对概念是库和框架。库的概念偏近于代码的堆集,是分层的概念,所以对应组件化。框架是结构化的代码,所以应用于模块化。框架是骨,模块化是肉。
比如,ReactiveCocoa是库,只是提供了响应式编码能力,而基于此的MVVM具体实现成果才叫框架,因为框架本身就有架构思想在里面。

举例
下面我们举例来说明。
组件化就比如公共的alert框,最初在许多页面都有使用,后面提取出一份相同的代码,其实就是基于代码复用的目的。

模块化就比如一个资讯功能,它本身只在这一个地方使用,没有复用的需求,但系统启动的时候要初始化它的数据,首页显示的时候要展示它的数据,显示红点的时候要拉取它的未读数。这样一来应用中就有很多地方涉及到它的代码。如果我们将它看做一个整体,那么资讯模块和主应用的耦合性就非常高了。所以我们也要把它封装成模块,把相关的代码放到独立的单元文件里,并提供公共方法,这就是高内聚的要求。

渐进式开发过程
当然这几个概念在服务端开发和客户端开发领域有些微差别,我下面的例子就从移动端开发的角度上进行辨析。

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

接下来我们逐步拆分这个产品。

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

1.组件
那么代码重构的第一步是什么呢?
将重复的代码合并成为一份,也就是重用。
我们来看组件化开发的定义,它的着重点就是重用,那这一步最后的结果就是提炼出一个个组件给不同的功能使用。

这里我们可以看一下依赖关系,是具体功能依赖提炼出来的组件,组件本身之间可能也有依赖关系,但一般不多。所以我们总结组件化开发的原则就是高重用,低依赖。当然这只是相对而言。
基于这样的认识,我们甚至于可以把资讯、问答、学院、直播等功能封装成组件,只不过这些组件比较大,依赖可能多些,不过本质上没有多少区别,而且实际上网上许多文章说所的模块化开发其实就是这种组件化的“模块”。

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

我们最开始定义这个虚拟产品的时候说,它有三个特点——高耦合、低内聚、无重用。而第一点组件化开发主要是解决了重用问题,提升了部分内聚,而耦合问题则没有涉及。
所以说我们上面可以将这个产品在逻辑上划分为资讯、问答、学院、直播四个模块,但在代码层面上它们却不是四个模块,因为它们的代码都是混杂在一起的。比如产品首页,可能推荐了部分资讯、显示了热门问答、推送了目前的直播,而这些功能的代码则是写在一起的;再比如程序启动的时候,这四个模块都需要初始化一些数据,而初始化数据的代码也是写在一起的;再比如程序需要显示未读消息数,而这几个模块都有自己的未读消息数逻辑。
如果未进行模块化开发的拆分,那么很多时候不同模块的同一类的代码都是直接写在一起的,比如系统启动的时候,我们会在启动方法里直接写多个模块的初始化代码。

而模块化开发就是为了解决这一问题,即提高内聚,将分属同一模块代码放到一起;降低耦合,将不同模块间的耦合程度弱化。
高内聚是目标,但是现状是有许多地方会用到多个模块,比如启动的时候会调用四个模块,首页会展示三个模块的界面。如果要高内聚,那么必然需要这些模块为不同的场景提供相同的方法,这就是说所有模块要实现同一套多个接口。这样主应用和模块之间的重耦合就变成了主应用和接口耦合,接口和模块耦合这样的松耦合。
但这样的简单模块只是轻模块,统一接口较少。而统一定义的接口越多,模块和统一接口的耦合就越高,也便是重模块。

而我们一般讲的路由问题其实只是解决模块间耦合的问题,并不是模块化开发的必然需求,更多时候是基于产品上的动态化要求,只不过我们一般都会在这个时间考虑这一事情而已,就像我们不会只做模块化开发同时不做组件化开发一样。

讲到这里,模块和组件的区别就已经很明显了。

作者:奇风
来源:CSDN
原文:https://blog.csdn.net/blog_jihq/article/details/79191008
版权声明:本文为博主原创文章,转载请附上博文链接!

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

网上有许多讲组件化、模块化等概念的文章,但大家一般都是将这两个概念混为一谈的,并没有加以区分。而且实际上许多人对于组件、插件、模块、子应用等概念的区别也不甚明了,甚至于许多博客文章专门解说这几个概念都有些谬误。
之前已经写了一篇文章专门对组件和模块两个概念进行辨析,现在我们对于更多的概念在更高的层次上进行辨析。
想分清这几个概念我觉得结合一下软件的渐进式开发场景更容易理解。但是下面的篇幅会比较长,所以按惯例还是先说结论,不耐烦的同学可以先看:

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


作者:奇风
来源:CSDN
原文:https://blog.csdn.net/blog_jihq/article/details/80669616
版权声明:本文为博主原创文章,转载请附上博文链接!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容

  • 在目前移动互联网时代,每个 APP 就是流量入口,与过去 PC Web 浏览器时代不同的是,APP 的体验与迭代速...
    斜杠时光阅读 13,878评论 4 139
  • 一、基础理论 1.什么是组件? 1.1组件化的定义 将实现页面某一部分功能的结构、样式和逻辑封装成为一个整体,使其...
    MelodyJie阅读 1,399评论 0 1
  • 很久没有你的消息?最近的你如何? 只能回头看看曾经留下的文字 觉得还真实存在着 想起也是弄人 原来想要你多为我写些...
    queeny23阅读 183评论 0 0
  • 1.行业八卦是拉近与候选人关系的有利工具 2.行业八卦注重市场积累 3.很多行业八卦只知道表象不明就里 4.行业八...
    73f3d790ca25阅读 401评论 0 0
  • 看看沿街的花,开的如火如荼。一点点的飘进眼里,就抓紧了你所有的目光!春景尚好,影影丛丛,两旁的人,互相叫卖。春会,...
    李朹朹阅读 164评论 0 0