前言
在提升前端代码质量之SOLID设计原则系列中文章提升前端代码质量之SOLID设计原则-SRP单一职责已经简单介绍了SOLID五种设计模式,不清楚可以移步到上文,本文不再赘述。
SOLID相关的文章索引:
- 提升前端代码质量之SOLID设计原则-SRP单一职责
- 提升前端代码质量之SOLID设计原则-OCP开放封闭原则
- 提升前端代码质量之SOLID设计原则-LSP里氏替换原则
- 提升前端代码质量之SOLID设计原则-ISP接口隔离原则
- 提升前端代码质量之SOLID设计原则-DIP依赖倒置原则
本文结合代码(React)主要讲解 SOLID 原则中的ISP - 接口隔离原则。
接口隔离原则(Interface Segregation Principle)
客户端不应该依赖它不需要的接口;类间的依赖关系应该建立在最小的接口上。
简单的说就是使用者不应该被迫依赖于它不使用的方法。比如我只是普通的发烧,我只需要去药店购买布诺芬就行了,但是药店只有捆绑销售:布诺芬+对乙酰氨基酚滴剂+对乙酰氨基酚栓+氨基比林等(降烧药类)。我只需要布诺芬,你给这么多显然是不对的,我吃了万一出事了咋办。
回到具体的设计层面来说,如果接口功能过多,非常容易违反单一职责。
而对于我们的编码来说,就是从调用方的需求出发,需要调用什么,我就提供什么。
尽可能提供少接口或者分割多个接口,而不是堆积接口方法。
就拿之前我们的例子提升前端代码质量之SOLID设计原则-SRP单一职责里面的来说,例子中商品展示的图片我们把它抽离出来封装成一个image组件:
//src\page\ISP\Product.tsx
import React from 'react';
import { TaobaoCircleOutlined } from '@ant-design/icons';
interface IProduct {
img?: string;
title?: string;
price?: number;
discount?: number;
storeName?: string;
id?: string;
}
interface IShowProductProps {
data: IProduct,
}
export default (props: IShowProductProps) => {
const { data: productItem } = props;
return <>
<div
style={{
padding: '16px',
margin: '8px',
display: 'flex',
flexDirection: 'column',
border: '1px solid #f2f2f2',
width: '234px',
height: '316px'
}}>
<img src={productItem.img} />
<h3
style={{
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis'
}}
>{productItem.title}</h3>
<div>
<span
style={{
color: 'red'
}}
>
¥{(productItem.price * (productItem.discount || 1)).toFixed(2)}
</span> 
{productItem.discount && <span style={{ textDecoration: 'line-through', opacity: '0.6' }}>¥{productItem.price.toFixed(2)}</span>}
</div>
<div>
<TaobaoCircleOutlined style={{ fontSize: '12px', color: '#fd3f31' }} />
<span style={{ opacity: '0.6', fontSize: '12px' }}> {productItem.storeName}</span>
</div>
</div>
</>
}
封装Image组件过后:
//src\page\ISP\Image.tsx
import React from "react"
const Image = (props: { img?: string }) => {
const { img } = props
return <>
<img src={img} />
</>
}
export default Image;
//src\page\ISP\Product.tsx
import React from 'react';
import { TaobaoCircleOutlined } from '@ant-design/icons';
import Image from './Image'
...
export default (props: IShowProductProps) => {
const { data: productItem } = props;
return <>
<div
style={{
padding: '16px',
margin: '8px',
display: 'flex',
flexDirection: 'column',
border: '1px solid #f2f2f2',
width: '234px',
height: '316px'
}}>
<Image {...productItem}/>
...
</div>
</>
}
能看到Image组件的props接收productItem:IProduct里面的属性:
interface IProduct {
img?: string;
title?: string;
price?: number;
discount?: number;
storeName?: string;
id?: string;
}
其实Image只需要一个属性:图片的url(这里是img),但是却接收除了img属性以外,还接收了额外属性(title、price、discount、storeName、id)。
正确的传参方式:
//src\page\ISP\Product.tsx
import React from 'react';
import { TaobaoCircleOutlined } from '@ant-design/icons';
import Image from './Image'
...
export default (props: IShowProductProps) => {
const { data: productItem } = props;
return <>
<div
style={{
padding: '16px',
margin: '8px',
display: 'flex',
flexDirection: 'column',
border: '1px solid #f2f2f2',
width: '234px',
height: '316px'
}}>
<Image img={productItem.img}/>
...
</div>
</>
}
接口隔离原则最重要的就是,从使用者角度出发定义接口方法。像antd这些组件库,都提供了按需加载能力,这个其实从某种意义上来说就是接口隔离,因为对于不需要的功能我们不必要都跑一遍。
最后
接口隔离原则ISP理解相对简单,也就没啥总结的了
相关的代码已经整理成一个仓库上传至github,感兴趣可以结合仓库代码阅读: REACT-SOLID