I
IP, Interface Segregation Principle)对於客户端,切分成许多个小型的介面,比一个通用的介面好,除此之外,介面不应该定义不相关的方法
以 Typescript 来举例子说明(因为 Typescript 有 Interface 关键字):
interface MyClock {
currentTime: Date; // 定义 currentTime 需为 Date 形式
setTime(d: Date); // 定义 setTime 这个抽象方法
}
interface MyAlertClock {
alertWhenTimeout: Function // 定义 alertWhenTimeout 需为 Function 形式
}
class Clock implements MyClock, MyAlertClock{
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
alertWhenTimeout() {
if ( this.currentTime <= Date.now() ) {
console.log('time has timeout!');
}
}
这里的时钟要实作(implements)MyClock 这个介面,还需要先有 currentTime 才能 setTime,但是只要实现 MyClock 这个介面,Clock 就是一个正常的时钟,介面之间不互相干扰(MyClock 与 MyAlertClock各自独立),像 MyAlertClock 算是一个增强的介面,根据需要而实现。
而 React 类似的做法是依靠 PropTypes 以及搭配 DefaultProps。
举例而言:
class ProductTable extends Component {
...
render() {
const product = {id: 1, content: '杯子', price: 200};
return (
<div>
<ProductDetail product={product}
</div>
)
}
}
class ProductDetail extends Component {
static propTypes = {
product: PropTypes.object.isRequired,
};
render() {
return (
<tr>
<td>Id: {this.props.product.id}</td>
<td>Content: {this.props.product.content}</td>
</tr>
)
}
}
上方这个例子,可以很明显的看见 ProductTable 是将整个 product (Object) 传进了 ProductRow ,但事实上 ProductRow 真正使用的值只有 Id 与 Content,如果今天我们要做测试,我们就需要 Mock 整个 Product不然就会出现问题,而介面隔离原则告诉我们将介面切分到最细,不要有不相关的方法。
以下为更改後程序码:
class ProductTable extends Component {
...
render() {
const product = {id: 1, content: '杯子', price: 200};
return (
<div>
...
<ProductDetail id={product.id} name={product.content}/>
...
</div>
);
}
...
}
class ProductDetail extends Component {
static propTypes = {
id: PropTypes.number.isRequired,
content: PropTypes.string.isRequired,
};
render() {
return (
<tr>
<td>Id: {this.props.id}</td>
<td>Content: {this.props.content}</td>
</tr>
)
}
}
D
IP, Dependency Inversion Principle)用户端参照的必须是介面(抽象)而不是物件
举例而言:
const Class = ({classroom, grade}) => (
<li>{classroom}'s grade is {grade}</li>
)
const ListClass = ({data}) => (
<ul>{
data.map(item=>(
<Class key={item.name}
classroom={item.classroom} grade={item.grade} />
))
}
</ul>
);
ReactDOM.render(
<ListClass data={[
{classroom:"301",grade:"三年级"},
{classroom:"201",grade:"二年级"}
]} />,
document.getElementById('root')
);
乍看之下,这写法是没问题的,但如果这时候有另外一个元件也要使用 ListClass
时并且希望用不同呈现方式,这时候就会有问题了,可能就不能复用 ListClass
这个元件而要另外新增,因此这时候应该使用的是依赖倒转原则,使得 ListClass 不要依赖於物件而是依赖於抽象。
const ListClass = ({data, ItemComponent}) => (
<ul>{
data.map(item=>(
<ItemComponent key={item.name}
{...item} />
))
}
</ul>
); // 这里的 ItemComponent 就是抽象
ReactDOM.render(
<ListClass data={[
{classroom:"301",grade:"三年级"},
{classroom:"201",grade:"二年级"}
]}
ItemComponent={Class}/>,
document.getElementById('root')
);
>>: [Day 29] - 手把手跨出第一步!– 烧录闪烁程序到Arduino Part.2
⚠行前通知 考量到有些人可能还没学过Python,然後我的主题又是定为从HTML到Python爬虫的...
Web API Open data是一种Web API,使用HTTP请求来执行其他系统提供功能来存取...
学习目标 本篇内容为阅读官方文件 Get data from a server 的笔记内容。 接续 ...
强型闯入DenoLand[35] - 完赛心得 年度回顾 今年对笔者我来说是相当特别的一年,从升上...
在 React 中,允许直接用 HTML 来建立表单, 但使用 JavaScript functio...