React 应用 SOLID 原则 03
里氏替换原则(LSP)
里氏替换原则可以理解为对象之间的一种关系,子类型对象可以替换为超类型对象。这个原则严重依赖类继承来定义超类型和子类型关系,但它在 React 中可能不太适用,因为我们几乎不会处理类,更不用说类继承了。虽然远离类继承会不可避免地将这一原则转变为完全不同的东西,但使用继承编写 React 代码会使代码变得糟糕(React 团队不推荐使用继承)。因此,对于这一原则不在过多解释。
接口隔离原则(ISP)
定义:客户端不应该依赖它不需要的接口
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| type Video = { title: string duration: number coverUrl: string }
type Props = { items: Array<Video> }
const VideoList = ({ items }) => { return ( <ul> {items.map(item => <Thumbnail key={item.title} video={item} /> )} </ul> ) }
|
Thumbnail 组件的实现
1 2 3 4 5 6 7
| type Props = { video: Video, };
const Thumbnail = ({ video }: Props) => { return <img src={video.coverUrl} />; };
|
Thumbnail 这个组件非常简单,但它有一个问题,他希望将完整的视频对象作为 props 传入,但是仅有效的使用其属性之一(coverUrl)
除了视频,我们还需要渲染直播的缩略图,这两种媒体资源会混合在同一个列表中
定义直播类型:
1 2 3 4
| type LiveStream = { name: string; previewUrl: string; };
|
更新 VideoList 组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| type Props = { items: Array<Video | LiveStream>, };
const VideoList = ({ items }) => { return ( <ul> {items.map((item) => { if ("coverUrl" in item) { return <Thumbnail video={item} />; } else { } })} </ul> ); };
|
这时候就发现了一个问题,我们可以轻松区分视频和直播对象,但是不能将后者传递给 Thumbnail 组件,因为 video 和 liveStream 类型不兼容。他们包含了不同的属性来保存缩略图。视频对象调用 coverUrl,直播对象调用 previewUrl。这就使组件依赖了比实际更多的 props 的原因所在。
下面来重构 Thumbnail
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| type Props = { items: Array<Video | LiveStream>, };
const VideoList = ({ items }) => { return ( <ul> {items.map((item) => { if ("coverUrl" in item) { return <Thumbnail coverUrl={item.coverUrl} />; } else { return <Thumbnail coverUrl={item.previewUrl} />; } })} </ul> ); };
|
接口隔离主张最小化系统组件直接的依赖关系,使他们的耦合度降低,从而提高可复用性。