Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

实现一个观察者模式 #41

Open
YvetteLau opened this issue Jul 3, 2019 · 10 comments
Open

实现一个观察者模式 #41

YvetteLau opened this issue Jul 3, 2019 · 10 comments

Comments

@YvetteLau
Copy link
Owner

No description provided.

@into-piece
Copy link

redux的createStore方法

/**
 * 
 * @param {*} reducer 
 * @param {*} initState 
 * @returns obj = {
   getState ?: fn,
   dispatch ?: fn,
   subscriber ?: fn
 }
 */
const createStore = (reducer, initState) => {
  let store = initState;
  let listeners = [];
  const getState = () => {
    return store;
  };

  // 当执行dispatch更改状态操作时,store tree更新后,依次执行数组中的listener
  const dispatch = action => {
    store = reducer(store, action);
    listeners.foreach(listener => {
      listener();
    });
  };

  // store内部维护listener数组,用于存储所有通过store.subscrib注册的listener
  // store.subscrib返回unsubscrib方法,用于注销当前listener
  const subscribe = listener => {
    listeners.push(listener);
    return () => {
      listeners = listeners.filter(item => listener !== item);
    };
  };

  return {
    getState,
    dispatch,
    subscribe
  };
};

@Liruimin2
Copy link

观察者模式又叫做发布—订阅模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知和更新。观察者模式提供了一个订阅模型,其中对象订阅事件并在发生时得到通知,这种模式是事件驱动的编程基石,它有利益于良好的面向对象的设计。
function getMessage(){
let message={};
this.register=function(messageType){
if(typeof message[messageType]=='undefined'){
message[messageType]=[]
}else{
console.log('消息已注册')}
}
//订阅
this.subScribe=function(messageType,func){
if(typeof message[messageType]!=='undefined'){
message[messageType].push(func)}else{
console.log('消息未注册,不能订阅')}
}
//发布
this.fire=function(messageType,arg){
if(typeof message[messageType]=="undefined"){
console.log('消息未注册不能发布')
return false}
let events={
type:messageType,
arg:arg||{}
}
message[messageType].map((item)=>{
item(events)})
}
}
let message = new MessageCenter();
message.register("nini");
message.subscribe("nini",subsfun);
message.fire("nini",'你好s');
function subsfun(events) {
console.log(events.type,events.arg);

}

@sinaine
Copy link

sinaine commented Jul 4, 2019

观察者模式有一个别名叫“发布-订阅模式”,或者说是“订阅-发布模式”,订阅者和订阅目标是联系在一起的,当订阅目标发生改变时,逐个通知订阅者。发布订阅者是观察者模式的一种别名。

var Jack = {
    subscribers: {
        'any': []
    },
    //添加订阅
    subscribe: function (type = 'any', fn) {
        if (!this.subscribers[type]) {
            this.subscribers[type] = [];
        }
        this.subscribers[type].push(fn); //将订阅方法保存在数组里
    },
    //退订
    unsubscribe: function (type = 'any', fn) {
        this.subscribers[type] =
            this.subscribers[type].filter(function (item) { 
                return item !== fn;
            }); //将退订的方法从数组中移除
    },
    //发布订阅
    publish: function (type = 'any', ...args) {
        this.subscribers[type].forEach(function (item) { 
            item(...args);    //根据不同的类型调用相应的方法
        });
    }
};

@KRISACHAN
Copy link

观察者模式

观察者模式:观察者(Observer)直接订阅(Subscribe)主题(Subject),而当主题被激活的时候,会触发(Fire Event)观察者里的事件。

//有一家猎人工会,其中每个猎人都具有发布任务(publish),订阅任务(subscribe)的功能
    //他们都有一个订阅列表来记录谁订阅了自己
    //定义一个猎人类
    //包括姓名,级别,订阅列表
    function Hunter(name, level){
        this.name = name
        this.level = level
        this.list = []
    }
    Hunter.prototype.publish = function (money){
        console.log(this.level + '猎人' + this.name + '寻求帮助')
        this.list.forEach(function(item, index){
            item(money)
        })
    }
    Hunter.prototype.subscribe = function (targrt, fn){
        console.log(this.level + '猎人' + this.name + '订阅了' + targrt.name)
        targrt.list.push(fn)
    }

    //猎人工会走来了几个猎人
    let hunterMing = new Hunter('小明', '黄金')
    let hunterJin = new Hunter('小金', '白银')
    let hunterZhang = new Hunter('小张', '黄金')
    let hunterPeter = new Hunter('Peter', '青铜')

    //Peter等级较低,可能需要帮助,所以小明,小金,小张都订阅了Peter
    hunterMing.subscribe(hunterPeter, function(money){
        console.log('小明表示:' + (money > 200 ? '' : '暂时很忙,不能') + '给予帮助')
    })
    hunterJin.subscribe(hunterPeter, function(){
        console.log('小金表示:给予帮助')
    })
    hunterZhang.subscribe(hunterPeter, function(){
        console.log('小张表示:给予帮助')
    })

    //Peter遇到困难,赏金198寻求帮助
    hunterPeter.publish(198)

    //猎人们(观察者)关联他们感兴趣的猎人(目标对象),如Peter,当Peter有困难时,会自动通知给他们(观察者)

发布订阅模式

发布订阅模式:订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Topic),当发布者(Publisher)发布该事件(Publish topic)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。

 //定义一家猎人工会
    //主要功能包括任务发布大厅(topics),以及订阅任务(subscribe),发布任务(publish)
    let HunterUnion = {
        type: 'hunt',
        topics: Object.create(null),
        subscribe: function (topic, fn){
            if(!this.topics[topic]){
                  this.topics[topic] = [];  
            }
            this.topics[topic].push(fn);
        },
        publish: function (topic, money){
            if(!this.topics[topic])
                  return;
            for(let fn of this.topics[topic]){
                fn(money)
            }
        }
    }

    //定义一个猎人类
    //包括姓名,级别
    function Hunter(name, level){
        this.name = name
        this.level = level
    }
    //猎人可在猎人工会发布订阅任务
    Hunter.prototype.subscribe = function (topic, fn){
        console.log(this.level + '猎人' + this.name + '订阅了狩猎' + topic + '的任务')
        HunterUnion.subscribe(topic, fn)
    }
    Hunter.prototype.publish = function (topic, money){
        console.log(this.level + '猎人' + this.name + '发布了狩猎' + topic + '的任务')
        HunterUnion.publish(topic, money)
    }

    //猎人工会走来了几个猎人
    let hunterMing = new Hunter('小明', '黄金')
    let hunterJin = new Hunter('小金', '白银')
    let hunterZhang = new Hunter('小张', '黄金')
    let hunterPeter = new Hunter('Peter', '青铜')

    //小明,小金,小张分别订阅了狩猎tiger的任务
    hunterMing.subscribe('tiger', function(money){
        console.log('小明表示:' + (money > 200 ? '' : '不') + '接取任务')
    })
    hunterJin.subscribe('tiger', function(money){
        console.log('小金表示:接取任务')
    })
    hunterZhang.subscribe('tiger', function(money){
        console.log('小张表示:接取任务')
    })
    //Peter订阅了狩猎sheep的任务
    hunterPeter.subscribe('sheep', function(money){
        console.log('Peter表示:接取任务')
    })

    //Peter发布了狩猎tiger的任务
    hunterPeter.publish('tiger', 198)

    //猎人们发布(发布者)或订阅(观察者/订阅者)任务都是通过猎人工会(调度中心)关联起来的,他们没有直接的交流。

@mark-0609
Copy link

mark-0609 commented Jul 4, 2019

let data = {price: 5, count: 10, res: 50}
let target = null
class Observer {
    constructor () {
        this.array = []
    }
    subscribe() {
        if( target && !this.array.includes(target)) {
            this.array.push(target)
        }
    }
    notify() {
        this.array.forEach(sub => sub())
    }
}

Object.keys(data).forEach(key => {
    let internalValue = data[key]
    const obs = new Observer()
    Object.defineProperty(data, key, {
        get() {
            obs.subscribe()
            console.log('get:' +internalValue)
            return internalValue
        },
        set(val) {
            internalValue = val
            console.log('set:'+ val)
            obs.notify()
        }
    })
});


function watcher(func) {
    target = func
    target()
    target = null
}

watcher(() => {
    data.res = data.price * data.count
})```

@Tcdian
Copy link

Tcdian commented Jul 5, 2019

const observer = (function() {
    let subscribers = []

    function publish(news) {
        subscribers.forEach((subscriber) => {
            subscriber(news)
        })
    }

    function subscribe(subscriber) {
        const index = subscribers.length
        subscribers = [...subscribers, subscriber]
        return () => {
            subscribers = [
                ...subscribers.slice(0, index), 
                ...subscribers.slice(index + 1)
            ]
        }
    }

    return {
        publish,
        subscribe
    }
})()

@jodiezhang
Copy link

//发布者 Subject 构造函数
function Subject(name){
    this.name = name,
    this.observerList=[]
}
Subject.prototype.registerOberver = function (observer) {
    if(this.observerList.indexOf(observer)==-1){
           this.observerList.push(observer)
    }
    
}
Subject.prototype.removeOberver = function (observer) {
    if(this.observerList.indexOf(observer))
       this.observerList.pop(observer)
    
}

Subject.prototype.refreshData = function (temp,humiditiy,pressure) {
          for(observer of this.observerList){
              observer.update(temp,humiditiy,pressure)
          }
}


//观察者 Observer 构造函数
function Observer(name){
    this.name = name
}
Observer.prototype.update = function(temp,humiditiy,pressure){
     console.log('I am observer '+ this.name)
     console.log('new temperature is '+ temp)
     console.log('new humidity is '+ humiditiy)
     console.log('new pressure is '+pressure)
}

//造几个观察者的实例
var observer1 = new Observer('熊熊')
var observer2 = new Observer('兔兔')
var observer3 = new Observer('羊羊')

//造一个发布者的实例
var subject = new Subject('发布者猪猪')
//在发布者中注册
subject.registerOberver(observer1)
subject.registerOberver(observer2)
subject.registerOberver(observer3)
//发布者有新的数据出现
subject.refreshData('28','80','65')
//在发布者中移除一个观察者
subject.removeOberver(observer3)
//发布者有新的数据出现
subject.refreshData('23','64','64')






I am observer 熊熊
new temperature is 28
new humidity is 80
new pressure is 65
I am observer 兔兔
new temperature is 28
new humidity is 80
new pressure is 65
I am observer 羊羊
new temperature is 28
new humidity is 80
new pressure is 65
I am observer 熊熊
new temperature is 23
new humidity is 64
new pressure is 64
I am observer 兔兔
new temperature is 23
new humidity is 64
new pressure is 64

参考:
headfirst设计模式

@luohong123
Copy link

luohong123 commented Jul 6, 2019

观察者模式

官方的解释是定义对象间的一种一对多的依赖关系,让多个观察者同时监听某一个主题现象,当一个对象的状态发生改变时,会通知所有观察者对象,所有依赖于它的对象都得到通知并被自动更新。
比如我们订阅报纸,报社是观察者,订阅报纸的人是被观察者,当有新报纸需要发布时,报社只需要通知订阅人,订阅人就能获取到新闻。

 function Observable(){
  // 保存事件和方法
  this.handles = {};
 }
 Observable.prototype={
  // 传入事件类型type和事件处理handle
  on: function (type, handle) {
   if(!this.handles[type]){
    this.handles[type] = [];
   }
   this.handles[type].push(handle);
  },
  emit: function () {
   // 通过传入参数获取事件类型
  var type = Array.prototype.shift.call(arguments);
   if(!this.handles[type]){
    return false;
   }
 for (var i = 0; i < this.handles[type].length; i++) {
    var handle = this.handles[type][i];
    //执行事件
   handle.apply(this, arguments);
   }
  },
  off: function (type, handle) {
   handles = this.handles[type];
   if(handles){
    if(!handle){
     handles.length = 0; // 清空数组
   }else{
 for (var i = 0; i < handles.length; i++) {
      var _handle = handles[i];
      if(_handle === handle){
       handles.splice(i,1);
      }
     }
    }
   }
  }
 }
var test1 =  new Observable();
 test1.on('星期', function (day) {
 console.log('星期: '+ day); // 
 });
 test1.emit('星期','一'); 
 var test2 = new Observable();
 var fn1 = function (day) {
  console.log('星期: '+ day); 
 };
 var fn2 = function (day) {
 console.log('星期: '+ day); 
 };
 test2.on('星期', fn1);
 test2.on('星期', fn2);
 test2.emit('星期','二');
 test2.off('星期', fn1);
 test2.emit('星期','三');
 test2.off('星期');
 test2.emit('星期','四');

@MissNanLan
Copy link

观察者模式(Observer Pattern)与发布/订阅模式(Publish /Subscribe Pattern)
![image.png](https://upload-images.jianshu.io/upload_images/4092152-2d0f0549d80e1195.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

这两种模式都是属于行为模式(Behaviral Patterns)
![image.png](https://upload-images.jianshu.io/upload_images/4092152-acfede46bfc3f431.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

1、 在观察者模式中,主题维护可观察列表,因此主题知道当状态发生变化时如何通知观察者。然而在发布/订阅者不需要相互理解,他们只需在中间层消息代理(或消息对立)的帮助下进行通信

2、观察者模式主要以同步的实现的;发布/订阅者主要以异步的方式实现(使用消息队列)

@chongyangwang
Copy link

chongyangwang commented Jul 14, 2019

1.观察者模式
楼上的大佬们各执一词啊 有说观察者就是发布订阅两者 是一回事么?写点伪代码看一看

// 声明一个漂亮的小姐姐 拥有 说 和 听 的功能 小姐姐到了谈婚论嫁的年龄

class  beautifulGirl {
      word;
      status
      listen:function(){
          switch (status)
             case  'beautiful':
             console.log('小姐姐说:谢谢我一直都很美')
             break;
             case: 'forever 20 years old':
             console.log('小姐姐说:Forever 18 years old')
             break;
             case: 'dalao':
             console.log('小姐姐说:不仅是大佬哦 还漂亮哦')
             break;
             default:
             console.log('小姐姐说:并不接受出自之外的任何status')
      },
      say: function(word,status){
         word =word
         status= status
      }
}

认识了几个网友  性别男   分别加了小姐姐的联系方式

 let man1 = new beautifulGirl()
 let man2  = new beautifulGirl()
 let man3  = new beautifulGirl()

 man1.say(‘小姐姐  仰慕已久’,beautiful)
 man1.listen()
 man2.say('小姐姐','dorever 20 year olds')
 man2.listen()
 man3.say('小姐姐''dalao')
 man3.listen()

上面这个例子举得有点不伦不类 搞得自己都有点模糊了 我并没有在开车 但是概念就是这个概念 一对多的关系 当一的某个属性发生改变 自动更新所有依赖于它的对象

1.发布订阅模式

小姐姐在想 mmp一个一个回信 回到啥时候 代码啥时候敲 直接一键群发 管你收到收不到 于是小姐姐开了一个公众号 将每天要发的消息 都推送到公众号 公众号再将这些消息发送到小姐姐的一排排仰慕者。 伪代码如下:

公众号有如下功能 推和被订阅

 class   messageCenter{
         subscribe(){

        },
        publish(){

       }
   }
   let   xiaojiejie = new messageCenter()
   xiaojiejie.publish('你喜欢我么?那你会不会给我的文章点赞  会不会去star  会不会来答题');

user 1,2,3 分别关注公众号

   let  user1 = new  new messageCenter()
   user1.subscribe()

   let  user2= new  new messageCenter()
   user2.subscribe()

    let  user3 = new  new messageCenter()
   user3.subscribe()

这时user1,2,3 都接收到了小姐姐的推送 然后小姐姐的star就多了起来。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests