二十三个经典的 设计模式 已经过完了 ,这里再把一些基本原则过一下,以便平时开发中可以更好的体会。
单一职责原则 SRP(Single Responsibility Principle)
There should never be more than one reason for a class to change." In other words, every class should have only one responsibility.
二十三个经典的 设计模式 已经过完了 ,这里再把一些基本原则过一下,以便平时开发中可以更好的体会。
There should never be more than one reason for a class to change." In other words, every class should have only one responsibility.
状态模式主要应用在游戏、工作流引擎中,其实就是有限状态机的实现,目前开发中还没有遇到过,此处留坑。
但状态模式也比较有意思,它可以将过多的 if...else... 或者 switch...case... 抽离出来,使得代码的扩展性更好一些。
举个例子,详细解释可以查看极客时间的 设计模式之美 讲的。
一个超级马里奥的例子,吃了蘑菇、吃了花都会有不同的状态进行转移。
命令模式主要应用在需要延迟执行请求、支持撤回的场景中,可能在文本编辑器中有应用,我目前没有使用过,这里就留坑了。
命令模式本质上就是将数据和操作封装为一个对象,实现操作的撤回、延迟等。
这里贴一下 Youtube 一个博主举的 计算器例子。
组合模式主要应用在符合树状结构的场景中,父节点和子节点实现统一接口,父节点委托给子节点进行执行。
其中父节点就可以当作组合对象,用户调用的时候无需关系是组合对象还是子对象,面向接口调用即可。
目前开发中还没有遇到过,此处留坑。
工厂模式是如果业务场景中需要创建多个类似的对象,然后充斥了大量的 if...else... ,此时可以将创建对象的部分抽离出来。
简单工厂模式就是直接抽离,什么都不改,只是将 if..else... 进行了转移。
工厂模式是每一个对象都创建一个工厂类,业务中先得到一个工厂,然后通过工厂得到对象。
抽象工厂模式是每一个工厂类可以生成多种对象。
GoF 中只有工厂模式和抽象工厂模式。
目前开发中还没有遇到过,此处留坑。
解释器模式应用在对自定义语法的解释上,自己规定一些新语法,然后通过解释器模式,语法的每种表达式进行细分,最终解释整个表达式。
可能会用在编译器、规则引擎上。
目前自己还没有遇到过,此处留坑。
备忘录模式主要是用于来防丢失、撤销、恢复等场景,定义是:在不违背封装原则的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便之后恢复对象为先前的状态。
需要三个类, Memento 类提供保存对象和得到对象的方法, Originator 类利用 Memento 类提供保存和读取自身状态的方法,Caretaker 类来记录所有的备份。
把 维基百科 的例子贴过来。
访问者模式主要作用是实现数据和操作的分离,可以在不改变数据类的同时,增加新的操作类型。
其主要通过「双分派」的思想实现。给原数据类传入一个 Visitor 方法,原数据类调用 Visitor 提供的方法,并将自己通过 this 传给 Visitor ,Vistior 实现相关操作。
目前开发中还没有遇到过,此处留坑。
原型模式在基于类的语言中作用大一些,当构造函数比较复杂,有一些耗时操作,此时通过 new 去创建对象不划算,可以通过 clone 的方法,直接基于已有对象 copy 一个。
js 属于基于原型的面向对象的编程语言,本身就是基于一个对象来生成另一个对象,并没有真正的类。
我们可以直接通过 Object.create 或者 json 序列化反序列化 copy 一个对象。
享元模式主要用于性能优化,当出现大量的重复对象时,为了防止内存被撑爆,可以抽离一些公共部分进行共享。
目前开发中还没有遇到过,此处留坑。
for...of.... 的原理是?
看下 维基百科 给的定义:
In object-oriented programming, the iterator pattern is a design pattern in which an iterator is used to traverse a container and access the container's elements. The iterator pattern decouples algorithms from containers; in some cases, algorithms are necessarily container-specific and thus cannot be decoupled.
如果我们定义了某个函数:
function getPhone(size, type, screen, price=100) {
...
}
网络请求中,我们一般使用 axios 库,支持用 Promise 风格调用。
axios
.get('/api/user', {
params: {
ID: '123',
},
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
axios
.post(
'/api/user',
{
firstName: 'wind',
lastName: 'liang',
},
{
headers: { 'Content-Type': 'application/json' },
}
)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
当我们使用第三方库的时候,常常会遇到当前接口和第三方接口不匹配的情况,比如使用一个 Table 的组件,它要求我们返回的表格数据格式如下:
{
code: 0, // 业务 code
msg: '', // 出错时候的提示
data: {
total: , // 总数量
list: [], // 表格列表
}
};
示例代码来源于极客时间课程,React Hooks 核心原理与实战,顺便推荐一下,很不错的课程
平常开发中一定遇到过这样的场景:发起异步请求,loading 状态显示,获取数据并显示在界面上,如果遇到错误还会显示错误状态的相关展示。
为了方便运行,先写一个 mock 数据的方法:
const list = {
page: 1,
per_page: 6,
total: 12,
total_pages: 2,
data: [
{
id: 1,
email: 'george.bluth@reqres.in',
first_name: 'windliang',
last_name: 'windliang',
avatar: 'https://reqres.in/img/faces/1-image.jpg',
},
{
id: 2,
email: 'janet.weaver@reqres.in',
first_name: 'Janet',
last_name: 'Weaver',
avatar: 'https://reqres.in/img/faces/2-image.jpg',
},
{
id: 3,
email: 'emma.wong@reqres.in',
first_name: 'Emma',
last_name: 'Wong',
avatar: 'https://reqres.in/img/faces/3-image.jpg',
},
],
};
export const getDataMock = () =>
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(list);
}, 2000);
});
如果需要实现一个全局的 loading 遮罩层,正常展示是这样的:

建议先看一下上篇 观察者模式 ,发布订阅模式和观察者模式本质上还是一样的,并且发布订阅模式也没有在经典的设计模式书 GoF 中出现,很多地方也直接把两者看成一种设计模式了。
GoF 的名字也有个有趣的故事,这里 贴过来: