不管是 React 和 Vue,在开发组件这块,都讲究利用组合来复用组件。但是如何将组件分解成多个子组件,有时候却是一件非常棘手的问题。拆分的不合理,非但不能提高组件的复用性,还会带来额外的维护成本。
在这篇设计易于扩展和收缩的软件open in new window论文中,作者介绍了一种软件设计思路,我们整理了下,发现不失为一种解决组件拆分的方法。今天我们就来讲一讲论文中的思路。
拆分原则
论文中的思路,大致可以归纳为一个基本原则,当满足如下四个条件的时候,我们可以从组件 A 中拆分出来组件 B:
- A 因为使用了 B,而变得更简单,更易于实现。
- B 不能使用 A,即不允许 A、B 之间存在循环依赖。
- B 可以作为独立单元被其他组件使用。
- 去除 B 以后,A 的功能没有实际意义。
现在我们结合样例来看看如何使用这个原则来拆分组件。
假设我们有一个视频播放器组件,有如下几个功能:
- 支持按照 16:9 的比例播放视频。
- 可以随时播放和暂停播放。
- 支持随意拖动视频播放进度。
- 支持静音。
- 支持全屏播放。
好的拆分实践
如上图所示,我们拆分出来四个组件:一个可控制高宽比open in new window的展示组件 AspectRatioBox,一个滑动条,按钮和图标。
现在我们来使用上面的拆分原则来考察一下 AspectRatioBox 这个组件。
组件 VideoPlayer 因为使用了 AspectRatioBox 而变得更加简单,否则 VideoPlayer 得自己实现高宽比的功能。
组件 AspectRatioBox 不使用组件 VideoPlayer 的任何功能,也没有任何场景需要使用到组件 VideoPlayer 的功能,满足要求。
除去组件 VideoPlayer,AspectRatioBox 可以单独使用,即组件 AspectRatioBox 可以复用在任何需要控制高宽比的地方。
组件 VideoPlayer 在去除组件 AspectRatioBox 以后,就丧失了视频播放的完整功能。
因此,AspectRatioBox 的拆分是符合原则的,即是一个好的拆分方案。
有时候我们在拆分的时候,并不会像这个例子中描述的一样这么明显。这种情况下,我们可以先大致进行拆分,然后在具体实现的时候不断调整。
不好的拆分实践
如上图所示,我们从 VideoPlayer 中拆分出一个 ActionsBar 组件。这个 ActionsBar 组件包含所有与用户交互相关的功能。
同样,结合上面的拆分原则,我们考察一下 ActionsBar 这个组件。
首先,在 VideoPlayer 是否因为使用了 ActionsBar 而变得简单这点上就存在讨论空间的。因为 ActionsBar 组件为了响应用户操作,势必需要传入各种回调函数。VideoPlayer 就需要在其内部定义这些回调函数,然后再传递给 ActionsBar。
组件 ActionsBar 不会使用 VideoPlayer 的任何功能,这点是符合要求的。
除去组件 VideoPlayer,ActionsBar 组件就丧失了存在的意义,无法在其他地方复用了。
组件 VideoPlayer 永远需要与组件 ActionsBar 一起使用,否则就没有播放视频的功能了。这点符合要求。
基于以上考察,我们可以认为组件 ActionsBar 的拆分是不合理的。
总结
在上面的例子中,我们通过文章开头的指导原则来对 UI 组件进行拆分。其实,这个指导原则还可以用在任何其他地方,比如函数、模块设计等。
组件的拆分不是一层不变的,随着代码的变迁,功能的迭代,最初的拆分方案已经不在符合上述的原则,那么我们就需要重新审视组件的拆分方案,来优化组件。
关注微信公众号,获取最新推送~
加微信,深入交流~