1.单例模式
class LoginFrame {
static instance;
constructor(state){
this.state = state;
if (!LoginFrame.instance) {
// 创建唯一实例的代码
LoginFrame.instance = this;
}
return LoginFrame.instance;
}
// 通过静态方法获取静态属性instance上是否存在实例,如果没有创建一个并返回,反之直接返回已有的实例
// 全局访问点,获取唯一实例
static getInstance(state){
console.log('instance--->', this, this.instance)
if(!this.instance){
this.instance = new LoginFrame(state)
}
return this.instance
}
}
const p1 = LoginFrame.getInstance('show')
const p2 = LoginFrame.getInstance('hide')
console.log(p1 === p2) // true
2.观察者模式
/*----------------------观察者模式---------------------------*/
// 要求:医院预约系统 当患者订阅了某一个科室 当某一个科室发布消息的时候 通知患者
// 目标对象(医院)
class Subject {
constructor() {
this.observerList = {}; // 医院的信息库(即观察者的集合),用来存储患者的信息 { xxx(科室名): [{ yyy(患者信息1) }, { yyy(患者信息1) }] }
this.type = ''; // 需要发布的科室
}
// 将患者添加进医院信息库
add(info) {
const { type } = info || {};
if (!this.observerList[type]) {
this.observerList[type] = [];
}
// 避免重复添加患者信息
if(this.observerList[type].find(item => item.name === info.name)) {
return;
}
this.observerList[type].push(info);
}
// 取消订阅
remove(info) {
const { type } = info;
if (!this.observerList[type].find(item => item.name === info.name)) {
console.log('抱歉,暂未收到您的订阅信息!')
return;
}
const index = this.observerList[type].findIndex(item => item.name === info.name);
this.observerList[type].splice(index, 1);
}
// 发布信息
notify(type) {
this.type = type;
this.observerList[this.type].forEach(item => {
item.update();
});
}
}
// 观察者(患者)
class Observer {
// 构造函数中记录患者的姓名 预约科室 预约时间
constructor(name, type, time) {
this.name = name; // 患者姓名
this.type = type; // 挂号科室
this.time = time; // 挂号时间
}
// 自己定义收到订阅消息后的方法(例如患者受到消息之后是否选择就诊还是放弃等)
update() {
console.log(`尊敬的${this.name}:您预约的${this.type}诊治将要在${this.time}开始了!`);
}
}
const subject = new Subject();
const observer1 = new Observer('李成', '口腔科', '2023-2-23');
const observer2 = new Observer('傅建良', '肛肠科', '2023-2-22');
const observer3 = new Observer('杨苏文', '妇产科', '2023-1-20');
const observer4 = new Observer('杨苏文', '妇产科', '2023-1-20');
subject.add(observer1);
subject.add(observer2);
subject.add(observer3);
subject.add(observer4);
subject.remove(observer2);
subject.notify('口腔科');
subject.notify('肛肠科');
subject.notify('妇产科');
3.发布订阅模式
/*----------------------发布订阅模式---------------------------*/
// 要求:医院预约系统 当患者通过一款APP订阅了某一个科室 当某一个科室发布的消息的时候 APP通知患者
// 相当于这款APP
class EventEmit {
constructor() {
this.events = {}; // 事件中心 格式: { 科室1: [ ], 科室2": [], 科室3: [] }
}
// 添加事件的方法
// type为订阅类型 callback为发布消息之后执行的回调函数
on(type, callback) {
if (!this.events[type]) {
this.events[type] = [];
}
this.events[type].push(callback);
}
emit(type, ...args) {
if (this.events[type]) {
this.events[type].forEach(callback => callback(...args));
}
}
remove(type, callback) {
if (!this.events[type]) {
console.log(`没有订阅该事件: ${type}`)
return;
}
delete this.events[type];
callback();
}
removeAll(callback) {
this.events = [];
callback();
}
}
const eventEmit = new EventEmit();
eventEmit.on('肛肠科', info => {
console.log('这是肛肠科的消息1', info)
});
eventEmit.on('肛肠科', info => {
console.log('这是肛肠科的消息2', info)
});
eventEmit.on('口腔科', info => {
console.log('这是口腔科的消息', info)
});
eventEmit.on('口腔科2', info => {
console.log('这是口腔科的消息2', info)
});
eventEmit.removeAll(() => {
console.log('删除全部订阅消息成功!')
});
eventEmit.remove('口腔科2', () => {
console.log('删除口腔科2的订阅消息成功!')
});
eventEmit.remove('妇产科', () => {
console.log('删除妇产科的订阅消息成功!')
});
eventEmit.emit('肛肠科', '李成');
eventEmit.emit('口腔科', '王明细');
eventEmit.emit('口腔科2', '多尔衮');
总结:
A,单例模式是一种常用的设计模式,它保证一个类只有一个实例,并提供了一个全局访问点。在JavaScript中,单例模式可以用来管理全局变量、缓存数据等。
B,观察者模式和发布订阅模式都是常用的事件模型,它们都实现了解耦合的目的,但是其本质上还是有一些区别的。
1. 对象间通信方式不同
观察者模式中,被观察者对象(Subject)直接向观察者(Observer)对象发送消息,即Subject直接调用Observer的方法,实现了一对多的关系。而在发布订阅模式中,发布者(Publisher)和订阅者(Subscriber)之间并没有直接的联系,而是通过消息代理(Message Broker)来进行通信,实现了多对多的关系。
2. 松散耦合程度不同
观察者模式中,被观察者对象及其观察者是相互知道的,即被观察者对象需要维护一个观察者列表,并且通知到每个观察者。而在发布订阅模式中,发布者和订阅者之间是松散耦合的,他们并不需要彼此知道,通过消息代理统一处理即可。
3. 代码复杂度不同
观察者模式在实现过程中需要手动管理观察者列表,增加和删除观察者比较麻烦,同时也容易出现循环引用等问题。而在发布订阅模式中,由于使用了消息代理,订阅和发布的过程变得简单明了,代码实现起来也更加容易。
总之,两种模式都是常用的事件模型,在项目开发中可以根据需求选择合适的模式。如果需要一对多的观察模式,则使用观察者模式;如果需要多对多的事件模型,则使用发布订阅模式。