定义
- 观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己
- 观察者模式是软件设计模式的一种常见的设计模式,又称发布订阅模式。在这种模式中,并不是单纯的一个对象调用另一个对象的方法,而是一个对象订阅另一个对象的特定活动并在其状态发生改变后获得通知,然后执行相应的操作。订阅者也称为观察者,而被观察的对象则被称为发布者或主题。当一个事件发生,发布者将会向所有订阅此事件的对象以事件对象的形式传递消息。
使用观察者模式的好处
- 支持简单的广播通信,自动通知所有已经订阅过的对象。
- 页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性。
- 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。
介绍
- 发布 & 订阅
- 一对多
实现
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/d4611088a3a6fe18ef60a36b70594337.jpeg)
<script>
//发布者,接受状态变化,触发每个观察者
class Subject {
constructor() {
this.state = 0 //记录信息的状态
this.observers = []//用来储存观察者
}
getState() { //获取状态信息
return this.state
}
setState(state) { //发布者状态信息的改变
this.state = state
this.notifyAllObservers()
}
attach(observer) { //添加每一个观察者
this.observers.push(observer)
}
notifyAllObservers() { //触发所有观察者执行updata()
this.observers.forEach(observer => {
observer.update()
})
}
}
// 观察者(订阅者),等待被触发
class Observer {
constructor(name, subject) {
this.name = name
this.subject = subject
this.subject.attach(this) //把每一个观察者对象添加到发布者的观察者数组队列中
}
update() {
console.log(`${this.name} update, state: ${this.subject.getState()}`)
}
}
// 测试代码
let s = new Subject();
let ob1 = new Observer('小明', s);
let ob2 = new Observer('小红', s);
let ob3 = new Observer('小花', s);
console.log(s);
s.setState("明天暴雨")
s.setState("后天初雪")
s.setState("大后天晴朗")
</script>
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/b8563656ebaf51a84efa6591eba6a2cf.jpeg)
<script>
//发布者
function Subject(){
this.list = [];
}
Subject.prototype = {
constructor : Subject,
// 订阅
on : function( obs ){
this.list.push( obs );
},
//发布
emmit : function(msg){
this.list.forEach( function( obs ){//obs其实是一个观察者的对象
obs.strategy( msg );
})
},
//删除
delete : function( obs ){
this.list.splice( this.list.indexOf(obs) , 1 )
}
}
// 订阅者;
function Obs( name ){
this.name = name;
}
Obs.prototype.strategy = function( msg ){//msg这个形参表示的是观察者里面的方法名
typeof this[msg] === "function" ? this[msg]() : "";//因为这里面有一个判断当this.函数名是一个方法则去执行这个方法
}
Obs.prototype.rain = function(){
console.log("明天下雨");
}
Obs.prototype.sunny = function(){
console.log("明天下雪");
}
var sub = new Subject();
sub.on( new Obs("小明") );
sub.on( new Obs("小红") );
sub.on( new Obs("小花") );
console.log(sub)
sub.emmit("rain");
</script>
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/2272fecdc43ddae1a53cff37e6031cc5.jpeg)
实战
function Observer(){
this.list = {};
}
Observer.prototype = {
constructor : Observer,
on : function( sub , type ){
type = type || "default";
// 判定对应类别之中是否为数组;
if(this.list[type] && this.list[type] instanceof Array){
// 如果是数组直接放入;
this.list[type].push(sub);
}else{
// 如果不是数组建立数组结构;
this.list[type] = [sub];
}
},
emmit : function(msg , type){
type = type || "default";
if(this.list[type] instanceof Array){
this.list[type].forEach( function( sub ){
sub.strategy( msg );
})
}
},
delete : function( sub , type ){
this.list[type].splice( this.list[type].indexOf(sub) , 1 )
}
}
//订阅者;
function Sub( name ){
this.name = name;
}
Sub.prototype.strategy = function( msg ){
typeof this[msg] === "function" ? this[msg]() : "";
}
Sub.prototype.happy = function(){
console.log("我好开心啊");
}
Sub.prototype.unhappy = function(){
console.log("我好难过啊");
}
// 黑粉 ;
function Sub2( name ){
this.name = name;
}
Sub2.prototype.strategy = function( msg ){
typeof this[msg] === "function" ? this[msg]() : "";
}
Sub2.prototype.happy = function(){
console.log("我好难过");
}
Sub2.prototype.unhappy = function(){
console.log("我号开心");
}
var obs = new Observer();
obs.on( new Sub("订阅者1") );
obs.on( new Sub("订阅者2") );
obs.on( new Sub("订阅者3") );
obs.on( new Sub("订阅者4") );
obs.on( new Sub2("订阅者5") , "heifen" );
obs.on( new Sub2("订阅者6") , "heifen" );
// console.log(obs)
obs.emmit("happy" );
obs.emmit("happy","heifen" );
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/49459944638d343dbdeac45bd86a1475.jpeg)