设计模式学习与应用【玩转前端】
一、前言
我开始几年的开发中几乎没有使用过设计模式。前端常见的设计模式,我看过好几遍,模式名称记得很清楚,但是具体内容和原理,我印象很模糊。
之所以记不住,用不上,原因两点,大部分功能比较简单,开发时也就用简单的方案进行实现了;对设计模式的理解没有透彻,不会用。
我感觉自己最近有高效率学习的buff,所以试着重新理解这个知识点。
二、边学边用
之前学习新技术的时候,看一遍文档或者文章,记忆并不深刻,后来发现自己对新技术的掌握程度在于自己是否真实的实现过。也就是常说的“好记性不如烂笔头”。而且我不擅长过目不忘,我需要理解了才能更好的记忆。
对于前端设计模式的学习,我采用了知识点介绍+功能代码的模式,方便学习、理解和记忆。其中知识点介绍大部分来自我参考的文章,参考文章会列在文章底部。(都是很优秀的文章)
2.1 外观模式
2.1.1 介绍
外观模式为子系统中的一组接口提供一个统一的高层接口,使子系统更容易使用。简而言之外观设计模式就是把多个子系统中复杂逻辑进行抽象,从而提供一个更统一、更简洁、更易用的API。
2.1.2 应用场景
很多我们常用的框架和库基本都遵循了外观设计模式。我们在实际开发中复杂的功能处理比如将某些复杂逻辑抽离进行封装,对外仅提供一个API即可,也是对外观模式的应用
2.1.3 简单小实例
我把之前做的功能简化了一下分享出来。
- 三个私有方法分别是_userBaseInfo(获取用户基础信息)、_userAddressInfo(获取用户的订单信息)、_userOrderInfo(获取用户的收货地址);
- 对外提供的方法是getUserInfo(获取用户的购物信息);
- 将内部的数据处理封装成一个方法提供出来,这样一个外观模式就实现了。
/**
* 用户-基础信息
*/
const _userBaseInfo = () => {
const obj = {
name: '张三',
phone: '123456',
sex: '男',
};
return obj;
};
/**
* 用户-收货地址信息
*/
const _userAddressInfo = () => {
const obj = {
province: '北京市',
city: '北京市',
region: '昌平',
};
return obj;
};
/**
* 用户-订单信息
*/
const _userOrderInfo = () => {
const obj = {
orderNo: '123',
price: '129',
goodName: '帽子',
};
return obj;
};
/**
* 用户-购物信息
*/
const getUserInfo = () => {
const baseInfo = _userBaseInfo();
const addressInfo = _userAddressInfo();
const orderInfo = _userOrderInfo();
const obj = {
...baseInfo,
...addressInfo,
...orderInfo,
};
return obj;
};
const userInfo = getUserInfo();
console.log({ userInfo });
// 打印结果
// {
// userInfo: {
// name: '张三',
// phone: '123456',
// sex: '男',
// province: '北京市',
// city: '北京市',
// region: '昌平',
// orderNo: '123',
// price: '129',
// goodName: '帽子'
// }
// }
2.2 代理模式
2.2.1 介绍
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。
2.2.2 应用场景
- 一些内部类不想或者不能直接被外部引用,可以使用代理类作为和外部的连接;
- 功能扩展,无需修改委托类,在代理类增加需要的功能就能实现功能扩展,比如增加消息通知、日志、缓存等。
2.2.3 简单小实例
- 一般二手书网站提供购买和出售书籍两种交易方式;
- 多抓鱼是我常用的二手书平台,它可以看做是一个代理服务,同时多抓鱼的配送服务使用的顺丰这种快速送货和取货的服务;
/**
* 二手书网站 提供购买和出售两种交易方式
*/
class BookTrading {
// 购买图书
buyBook(props) {
props = props ? props : {};
let res = '购买了' + props.amount + '本' + props.name;
console.log(res);
}
// 出售图书
recoveryBook(props) {
props = props ? props : {};
let res = '出售了' + props.amount + '本' + props.name;
console.log(res);
}
}
/**
* 多抓鱼二手书交易平台
*/
class Duozhuayu extends BookTrading {
constructor() {
super();
}
buy(props) {
// 购买图书
this.buyBook(props);
}
buyDelivery(props) {
// 购买图书
console.log('顺丰一日送达:');
this.buyBook(props);
}
recovery(props) {
// 出售图书
this.buyBook(props);
}
recoveryPickUp(props) {
console.log('顺丰上门取件:');
this.recoveryBook(props);
}
}
const duozhuayu = new Duozhuayu();
duozhuayu.buy({ name: '书店日记', amount: 2 });
duozhuayu.buyDelivery({ name: '中国地理杂志', amount: 5 });
duozhuayu.recovery({ name: '乌合之众', amount: 1 });
duozhuayu.recoveryPickUp({ name: '局外人', amount: 1 });
// 打印结果
// 购买了2本书店日记
// 顺丰一日送达:
// 购买了5本中国地理杂志
// 购买了1本乌合之众
// 顺丰上门取件:
// 出售了1本局外人
2.3 观察者模式
2.3.1 介绍
观察者模式又称发布订阅模式(Publish/Subscribe Pattern),被观察对象(subject)维护一组观察者(observer),当被观察对象状态改变时,通过调用观察者的某个方法将这些变化通知到观察者。
2.3.2 应用场景
很多类似消息传递的场景都适用观察者模式,比如商品订阅到货提醒、招聘中的求职者和HR的通信等
2.3.3 简单小实例
以电商中商品到货提醒功能为例,这个小例子帮助我很好的理解了观察者模式。
观察者模式中,被观察者(Subject)和观察者(Observer)是必不可少的,整个使用过程都是它俩的信息置换。
被观察者Subject:
- 维护观察者列表。例子中即消费者列表。
- 定义添加和取消观察的方法。例子中即提供给消费者添加到货提醒和取消到货提醒的功能;
- 当监测到自身变化之后,通过调用自己的notice方法依次通知每一个有通知权限的观察者,例子中即添加了到货提醒的消费者。
观察者Observer:
- 定义update方法,提供给被观察者调用。例子中即到货之后消费者接收的通知消息。
- 自定义方法,实现业务逻辑。例子中即添加了到货通知的消费者实际接收到的消息内容。
流程图如下:
定义观察者类
// 观察者
class Observer {
constructor(name) {
this.name = name;
}
update(info) {
// 只有添加到货通知权限的才进行到货提醒
if (info.notifyType === 'add') {
this.remindArrival(info.goodName);
} else if (info.notifyType === 'cancel') {
console.log(`${this.name}取消到货提醒,不会接受到系统提醒。`);
} else {
console.log(`${this.name}没有添加到货提醒`);
}
}
// 到货提醒
remindArrival(info) {
console.log(`亲爱的${this.name},您关注的宝贝${info}已到货!`);
}
}
定义被观察者类
class Subject {
constructor() {
this.observerList = [];
}
// 订阅
subscribe(observer) {
observer.notifyType = 'add';
this.observerList.push(observer);
}
// 取消订阅
unsubscribe(observerRemove) {
observerRemove.notifyType = 'cancel';
this.observerList.push(observerRemove);
}
// 到货提醒
notice(good) {
this.observerList.forEach(observer => {
let obj = {
...good,
...observer,
};
observer.update(obj);
});
}
}
实例化之后的调用
const subject = new Subject();
const obsA = new Observer('消费者A');
const obsB = new Observer('消费者B');
const obsC = new Observer('消费者C');
// obsA obsB 添加了到货提醒
subject.subscribe(obsA);
subject.subscribe(obsB);
// obsC 取消到货提醒
subject.unsubscribe(obsC);
// 商品外套已到货
const goodCoat = {
goodName: '外套',
};
// 通知添加到货提醒的消费者
subject.notice(goodCoat);
打印输出
亲爱的消费者A,您关注的宝贝外套已到货!
亲爱的消费者B,您关注的宝贝外套已到货!
消费者C取消到货提醒,不会接受到系统提醒。
通过打印的结果可以看出,添加到货提醒的消费者能够收到商品到货通知,取消到货提醒的消费者则不会收到通知。
三、总结
学习下来,我发现实际开发中已经应用了某些设计模式,只是当时并不知道原来这样的功能设计是某个设计模式。
即便原本不擅长的技术,通过不断学习,可以从中找了新的开发思路。
我准备找时间,翻翻自己之前的代码,试试看有没有新的开发思路或者开发方案,即便是之前的代码不能轻易动它,也可以用在下一次的需求中。
作者:非职业「传道授业解惑」的开发者叶一一
简介:「趣学前端」、「CSS畅想」系列作者,华夏美食、国漫、古风重度爱好者,刑侦、无限流小说初级玩家。
如果看完文章有所收获,欢迎点赞👍 | 收藏⭐️ | 留言📝。
- 点赞
- 收藏
- 关注作者
评论(0)