17 July 2021
号外号外:我的新书《现代JavaScript库开发:原理、技术与实战》出版啦!!!快点我查看
号外号外:一组小而美的JavaScript迷你库!!!快点我查看
号外号外:猿辅导招聘前端,后端,客户端啦!地点:北京!!!快点我查看

最近文章写得少了,都是因为在填耦合架构的坑,人生苦短,填坑不完,o(╥﹏╥)o

在不断踩坑和填坑的过程中,我不禁感叹,怎么能写出这么糟糕的架构,其实比耦合架构更好怕的是,设计耦合架构,以及维护耦合架构的人意识不到问题的存在,坑是填不完的,要解决挖坑的人,所以我决定把这些经验分享出来,希望可以帮助大家

本文的标题稍微有些标题党,本文提到的架构是代码层面的架构,本文通过一个例子,向大家介绍耦合架构,拷贝架构,超类架构和组合架构的区别和优劣

背景

本文用上传组件作为例子,一般业务中的上传组件都有自己的逻辑,现在假设我们有如下多个不同的上传组件:

  • 文件上传组件,通用的上传组件
  • 图片上传组件,有自己的展示逻辑和图片处理等
  • 音频上传组件,有自己的展示逻辑和音频处理等
  • 路径上传组件,有自己的展示逻辑且参数也不同

现在让我们想一下,实现这些逻辑,代码该如何设计,在往下看之前,建议先看一下我的另一篇文章——图解7种耦合关系,下面会用到这里面提到的知识

耦合架构

耦合架构就是把代码都写在一起,这样就实现了公共逻辑只存在一份;然后内部存在很多条件判断,来实现不同的分支逻辑

相信大家都能看出来耦合架构的问题,心里也都有自己的答案,但耦合架构是怎么形成的呢?耦合架构大部分都是业务演进的结果,开始时业务只有一种,当来了新的业务时,可能开人员偷懒了,也可能是缺乏重构的勇气,就慢慢积累了下来,然后尾大不掉,渐渐失去了所有人的控制

耦合架构的优点大概只有节省设计时间了,因为不用设计,业务线性演变即可

耦合架构的问题在于难以维护,不同业务的逻辑紧紧交织在一起,系统复杂度会随着分支的数量指数级增长,一般随着时间的积累,很可能会逐渐失控,演变成下图这样

耦合架构对于改动非常不友好,极有可能牵一发而动全身,改不动,理不清;耦合架构对于修改Bug非常不友好,如同盲人摸象,难以排查;耦合架构对于阅读非常不友好,理清逻辑犹如管中窥豹,错综复杂

耦合架构演进到最后,很可能被弃坑,特别是人员变更,恰巧来了一个新的功能时,极有可能放弃前人的积累,另起炉灶

拷贝架构

耦合架构演进到最后很可能变为拷贝架构,这也是我在项目中看到的问题,同学们告诉我,这个有点复杂哦,建议你拷一份,别修改之前的代码

拷贝架构就是各个组件完全自成一份,每个都包含完成的功能,在写业务之前,就把之前的拷贝一份

拷贝架构的优点就是相互隔离,业务之间的演进不会相互影响

拷贝架构的缺点也很明显,公共逻辑被复制了多份,违反了DRY原则;特别是如果公共部分自身改动的话,可能会有研发效率加倍,或者逻辑不一致问题

超类架构

面对前面的问题,大家会做出不同的改进,超类架构是一个典型的方向,面向对象思维建议用继承来解决泛化问题,通过抽象一个上传基类,可以解决公共逻辑的问题,不同业务的差异,可以通过子类来泛化实现

超类的优点在于解决了泛化和公共的问题,通过抽象继承隔离了两部分逻辑

超类的问题在于,继承本身就脆弱,大部分前端的OOP能力也良莠不齐,存在四不像设计和啥都往超类塞的问题;超类虽然隔离了公共逻辑,但还是会将公共逻辑已接口的方式暴露给子类,子类需要感知父类的设计;父类很难设计的良好,面对发散的业务,后面父类的迭代会越来越痛苦

超类架构依赖于良好的抽象,如果抽象不好,也会存在弃坑的问题,很有可能拷贝一份而放弃了超类的维护

组合架构

组合架构是更适合前端UI组件的架构,通过将页面拆分成功能独立的组件,再将组件组合到一起从而实现页面功能,在我们的例子中,可以将公共逻辑提取为一个功能单一的上传组件即可,其只包含上传逻辑处理,对外提供属性和回调函数

从架构图上来看和超类是相似的,但继承和组合是两个概念,组合是自下而上的,可逆的,上下层组件之间的耦合是松散的;继承是自顶而下的,不可逆的,父子组件之间的耦合是紧密的

组合架构依赖于设计良好的组件,需要遵从单一职责和开闭原则,设计糟糕的组件会让系统变的脆弱,组件要做到高内聚,低耦合,组件要做到面向参数设计,剥离业务

总结

本文通过一个例子,介绍了前端的4种设计模式,希望能够帮助大家,在解耦合的道路上有更多的选择

一般一个模块人人都觉得复杂,却又没人提出改进,那往往是设计存在问题,一般好的设计都是简单的

原文网址:http://yanhaijing.com/program/2021/07/17/coupling-and-composition/

微信公众号:颜海镜
关注微信公众号 颜海镜
微信支付二维码
赞赏支持 微信扫一扫