设计模式,是在软件设计开发过程中,针对特定问题或场景的较优解决方案。它可以帮助我们遇到相似的问题、场景时,能够快速找到更优的方式解决。
1. 设计模式需遵循的设计原则
- 单一职责原则:一个类只负责一个功能,如果功能过于复杂,最好让这个类只负责一部分逻辑。
- 开放封闭原则:对于类、函数、模块等软件实体是可扩展但不可修改的。
- 面向接口原则:调用者只需要关注接口,不必清楚接口内部的类如何实现的。
2. 发布-订阅模式:常考
发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到状态改变的通知。
订阅者把自己想订阅的事件注册到调度中心,当发布者发布该事件到调度中心,也就是该事件触发时,由调度中心统一调度订阅者注册到调度中心的处理代码。
1. 和观察者模式的区别
在观察者模式中,观察者会监听被观察者的变化,当被观察者变化时就会通知所有的观察者。
所以观察者模式中仅有发布者、订阅者两个,而发布-订阅模式则还有调度中心,负责处理发布者和订阅者的代码。
2. 手写实现:EventEmitter,支持事件的on,once,off,emit。
- on:注册事件的回调函数
- once:注册事件的回调函数,只执行一次
- off:删除一个回调函数
- emit:触发事件,执行回调函数
- offAll:删除事件的所有回调函数
class EventEmitter {
constructor() {
this.listener = {}; // 存储事件以及回调函数
}
on(event, callback) {
if (!this.listener[event]) {
this.listener[event] = []; // 初始化一个监听函数队列
}
this.listener[event].push(callback);
}
emit(event, ...args) {
if (this.listener[event]) {
this.listener[event].forEach((cb) => {
cb(...args);
})
}
}
off(event, callback) {
if (this.listener[event].includes(callback)) {
let index = this.listener[event].indexOf(callback);
this.listener[event].splice(index, 1);
}
if (this.listener[event].length == 0) { // 当没有回调函数时就移除该事件
delete this.listener[event];
}
}
once(event, callback) {
const wrapper = function(...args) { // 对回调函数进行包装,使其执行完毕自动被移除
callback.apply(this, args);
this.off(event, callback);
}
this.on(event, wrapper);
}
offAll(event) { // 删除某个事件的所有监听函数
if (this.listeners[event]) {
delete this.listeners[event];
}
}
}
/* 测试 */
let ee = new EventEmitter();
ee.on('eat', () => console.log('吃饭'));
ee.emit('eat');
3. 单例模式:常考
一个类只能构造出唯一的实例。
function Single(name) {
this.name = name;
}
Single.getInstance = function(name) { // 静态方法
if (this.instance) {
return this.instance;
} else {
this.instance = new Single(name);
return this.instance;
}
};
// 测试
let a = Single.getInstance('ins1');
let b = Single.getInstance('ins2');
console.log(a === b); // true
4. 其他模式
- 代理模式:在访问者和目标对象之间加一层代理,无法直接访问时可以通过代理实现授权和控制。
- 装饰器模式:在原来对象的基础上扩展功能或属性。
- 适配器模式:将一个接口转换成用户希望的另一个接口,使接口不兼容的类也可以一起工作。