JavaScript观察者模式原理与实现
观察者模式定义了对象间的一对多依赖关系。本文基于JavaScript语言,以双11促销为例,演示如何实现观察者对象自动接收状态变更通知。内容涵盖核心概念、完整代码实现及优化重构。
什么是观察者模式?
观察者模式(Observer Pattern)是一种常用的设计模式。它定义了一种“一对多”的依赖关系:当一个对象(被观察者)的状态发生改变时,所有依赖于它的对象(观察者)都会收到通知并自动更新。
简单来说,该模式涉及两个主要角色:
- 被观察者 (Observed):负责维护状态,并在状态变化时通知观察者。
- 观察者 (Observer):注册在被观察对象上,当收到通知时执行相应的处理逻辑。
第1步:场景模拟
为了更直观地理解,我们以电商促销活动为例进行模拟:
- 消费者(观察者/Observer):想要在双11购买特定商品的人。他们关注商品,希望能第一时间获取降价信息。
- 商品(被观察者/Observed):具体的待售商品实体。
- 商家(发布者/Publisher):改变商品价格或库存的一方。当商家调整价格时,作为发布者的身份触发通知。
在双11当天,商家修改了商品价格(发布消息),此时已经订阅该商品的所有消费者(观察者)都会收到降价通知。
第2步:原生代码实现
下面通过一段原生JavaScript代码来实现上述逻辑。我们将创建一个名为 shopObj 的对象来管理订阅和发布行为。
// 观察者设计模式 - 基础实现
// 创建一个发布者对象,代表商家
var shopObj = {};
// 商品列表,用于存储每个商品的订阅函数 [key: []],key为商品名
shopObj.list = [];
// 订阅方法
// key: 订阅的商品型号/名称
// fn: 接收到通知后执行的回调函数
shopObj.listen = function (key, fn) {
// 如果该商品还没有订阅者,初始化数组
if (!this.list[key]) {
this.list[key] = [];
}
// 将订阅函数存入对应商品的列表中
this.list[key].push(fn);
};
// 发布消息方法
shopObj.publish = function (key) {
// 获取该商品对应的所有订阅函数集合
var fns = this.list[key];
// 遍历执行所有订阅函数
// arguments 包含 publish 调用时传入的参数(如商品信息)
for (var i = 0, fn; fn = fns[i++]; ) {
// apply 绑定上下文,并将后续参数传递给回调函数
fn.apply(this, Array.prototype.slice.call(arguments, 1));
}
};
// --- 测试用例 ---
// A用户订阅华为手机降价通知
shopObj.listen("华为", function (model, price) {
console.log("A用户收到:" + model + "降价通知,当前价格可能是" + price);
});
// B用户也订阅华为手机
shopObj.listen("华为", function (model, price) {
console.log("B用户收到:" + model + "降价通知");
});
// C用户订阅小米手机
shopObj.listen("小米", function (model) {
console.log("C用户收到:" + model + "降价通知");
});
// 双11开始,商家发布消息
console.log("--- 双11商家发布消息 ---");
shopObj.publish("华为", "P30", "¥3999");
shopObj.publish("小米", "Mix4", "¥2999");
在上述代码中:
- listen(key, fn) 负责注册观察者。
- publish(key, ...args) 负责触发所有注册的回调,并将额外参数传递给它们。
第3步:代码重构与优化
原始实现中,list、listen 和 publish 都直接挂载在 shopObj 上。为了让代码更具通用性,我们可以将其封装为一个独立的工具对象 Event,并通过原型链或混合模式赋予其他对象事件能力。
// 观察者设计模式 - 重构实现
var Event = {
// 内部存储订阅关系
list: [],
// 订阅方法
listen: function (key, fn) {
if (!this.list[key]) {
this.list[key] = [];
}
this.list[key].push(fn);
},
// 发布方法
publish: function (key) {
var fns = this.list[key];
if (!fns || fns.length === 0) return; // 增加安全性检查
for (var i = 0, fn; fn = fns[i++]; ) {
fn.apply(this, Array.prototype.slice.call(arguments, 1));
}
}
};
// 辅助函数:将Event对象的方法混合到目标对象中
function initEvent(obj) {
for (let i in Event) {
obj[i] = Event[i];
}
}
// 创建商家对象
var shopObj = {};
initEvent(shopObj);
// 用户订阅
shopObj.listen("华为", function (model) {
console.log("用户A获悉:" + model + "有变动");
});
shopObj.listen("小米", function (model) {
console.log("用户B获悉:" + model + "有变动");
});
// 触发通知
shopObj.publish("华为", "Mate60");
shopObj.publish("小米", "14 Ultra");
重构后的代码逻辑更加清晰:
1. Event 对象作为一个独立的事件中心。
2. initEvent 将事件能力赋予任意对象,体现了面向对象的组合优势。
3. 增加了空值检查,防止发布未订阅的消息时报错。
总结
观察者模式是前端开发中非常基础且重要的设计模式,广泛应用于Vue/React的数据绑定、Node.js的Events模块以及DOM事件流中。通过实现一个简单的发布-订阅机制,我们可以解耦数据源与多个监听者,使代码结构更加灵活易维护。
以上就是JavaScript观察者模式原理与实现的详细内容,更多关于JavaScript设计模式与前端开发的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













