不管是 React 和 Vue,在開發組件這塊,都講究利用組合來復用組件。但是如何將組件分解成多個子組件,有時候卻是一件非常棘手的問題。拆分的不合理,非但不能提高組件的復用性,還會帶來額外的維護成本。
在這篇設計易於擴展和收縮的軟件論文中,作者介紹了一種軟件設計思路,我們整理了下,發現不失為一種解決組件拆分的方法。今天我們就來講一講論文中的思路。
拆分原則
論文中的思路,大致可以歸納為一個基本原則,當滿足如下四個條件的時候,我們可以從組件 A 中拆分出來組件 B:
- A 因為使用了 B,而變得更簡單,更易於實現。
- B 不能使用 A,即不允許 A、B 之間存在循環依賴。
- B 可以作為獨立單元被其他組件使用。
- 去除 B 以后,A 的功能沒有實際意義。
現在我們結合樣例來看看如何使用這個原則來拆分組件。
假設我們有一個視頻播放器組件,有如下幾個功能:
- 支持按照 16:9 的比例播放視頻。
- 可以隨時播放和暫停播放。
- 支持隨意拖動視頻播放進度。
- 支持靜音。
- 支持全屏播放。
好的拆分實踐
如上圖所示,我們拆分出來四個組件:一個可控制高寬比的展示組件 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 組件進行拆分。其實,這個指導原則還可以用在任何其他地方,比如函數、模塊設計等。
組件的拆分不是一層不變的,隨着代碼的變遷,功能的迭代,最初的拆分方案已經不在符合上述的原則,那么我們就需要重新審視組件的拆分方案,來優化組件。
常見面試知識點、技術解決方案、教程,都可以掃碼關注公眾號“眾里千尋”獲取,或者來這里 https://everfind.github.io 。