观察者模式,事件,监听,触发与推送

理论知识

观察者模式和发布订阅模式其实是一个东西,区别只是在于调度中心。

image.png

观察者模式定义了一种一对多的依赖关系,让多个观察者对象(或订阅者对象)同时监听同一个主题。这个主题对象在状态发送变化时,会通知所有的观察者对象(或订阅者对象),使得它们能够自动更新自己。

调度中心的作用之一,每个观察者对象(或者订阅者对象)的行为可能都不一样(方法名不一样),这个时候调度中心就能发挥作用,它提供“事件委托”的功能,主要是提供回调函数的关联。

两个问题

如何实现一个观察者模式

  • 非典型的例子,这并不是一个观察者模型 ```javascript // index3.jsx interface EventType { eventName: string; eventFn: (…args: any[]): any; }

class EventBus { const listeners: EventType[] = []; // 添加一个事件(主题) addEvent(event: EventType){} // 移除一个事件(主题) removeEvent(eventName){} // 触发一个事件(通知,主题发生了变化) trigger(eventName){} }

export const eventBus = new EventBus;

// index2.js import { eventBus } from ‘./index3.jsx’; import React from ‘react’; class ClassA extends React.Component { constructor(props) { super(props); this.state = { num: 0, } } componentDidMount(){ eventBus.addEvent({ eventName:’numOnchange’, // 订阅一个主题 eventEvent: () => { this.setState({ num: num + 1, }); } }) } render(){ return (

{this.state.num}
); } }

// index1.js import { eventBus } from ‘./index3.jsx’; import React from ‘react’; class ClassB extends React.Component { constructor(props) { super(props); } render(){ return (

); } }

  1. 为什么观察者模式可以实现数据的传递(状态的自动更新)
  2. <a name="QXYDc"></a>
  3. ##
  4. <a name="PZzGr"></a>
  5. ## 值的拷贝与值的引用
  6. [https://www.yuque.com/lijunyang/dk90s4/qdxd19#919b86d2](https://www.yuque.com/lijunyang/dk90s4/qdxd19#919b86d2)
  7. <a name="Cq0Bi"></a>
  8. #### 观察者,被观察者(主题)
  9. ```javascript
  10. // 观察者
  11. class Observer {
  12. constructor() {
  13. }
  14. update(val) {
  15. }
  16. }
  17. // 观察者列表(目标)
  18. class ObserverList {
  19. constructor() {
  20. this.observerList = []
  21. }
  22. add(observer) {
  23. return this.observerList.push(observer);
  24. }
  25. remove(observer) {
  26. this.observerList = this.observerList.filter(ob => ob !== observer);
  27. }
  28. count() {
  29. return this.observerList.length;
  30. }
  31. get(index) {
  32. return this.observerList(index);
  33. }
  34. }
  35. // 主题(目标)
  36. class Subject {
  37. constructor() {
  38. this.observers = new ObserverList();
  39. }
  40. addObserver(observer) {
  41. this.observers.add(observer);
  42. }
  43. removeObserver(observer) {
  44. this.observers.remove(observer);
  45. }
  46. notify(...args) {
  47. let obCount = this.observers.count();
  48. for (let index = 0; index < obCount; index++) {
  49. this.observers.get(i).update(...args);
  50. }
  51. }
  52. }
  53. const subject = new Subject();
  54. const classA = new Observer();
  55. const classB = new Observer();
  56. Subject.addObserver(classA);
  57. Subject.addObserver(classB);
  58. Subject.notify('发送一个字符串');

有趣的思路

如果将上面的代码与两个问题里的非典型的例子进行组合

  1. // index3.jsx
  2. interface EventType {
  3. eventName: string;
  4. eventFn: (...args: any[]): any;
  5. }
  6. interface EventData {
  7. eventName: string;
  8. paramData: any;
  9. }
  10. class EventMonitor {
  11. listeners = [];
  12. remove = function(eventName) {
  13. const arr = this.listeners.filter((temp) => {
  14. return temp.eventName !== eventName;
  15. });
  16. this.listeners = arr;
  17. }
  18. trigger = function(eventName, param) {
  19. this.listeners.forEach((item) => {
  20. if (eventName === item.eventName) {
  21. item.fn(param);
  22. }
  23. })
  24. }
  25. on = function(eventName, fn) {
  26. this.listeners.push({
  27. eventName,
  28. fn
  29. });
  30. }
  31. }
  32. class EventBus {
  33. const listeners: EventType[] = [];
  34. // 添加一个事件(主题)
  35. addEvent(event: EventType){}
  36. // 移除一个事件(主题)
  37. removeEvent(eventName){}
  38. // 触发一个事件(通知,主题发生了变化)
  39. trigger(eventName){}
  40. }

调度中心

  1. class PubSub {
  2. constructor() {
  3. this.subscribers = {}
  4. }
  5. subscribe(type, fn) {
  6. if (!Object.prototype.hasOwnProperty.call(this.subscribers, type)) {
  7. this.subscribers[type] = [];
  8. }
  9. this.subscribers[type].push(fn);
  10. }
  11. unsubscribe(type, fn) {
  12. let listeners = this.subscribers[type];
  13. if (!listeners || !listeners.length) return;
  14. this.subscribers[type] = listeners.filter(v => v !== fn);
  15. }
  16. publish(type, ...args) {
  17. let listeners = this.subscribers[type];
  18. if (!listeners || !listeners.length) return;
  19. listeners.forEach(fn => fn(...args));
  20. }
  21. }
  22. let ob = new PubSub();
  23. ob.subscribe('add', (val) => console.log(val));
  24. ob.publish('add', 1);

一个应用场景

image.png

  1. abstract class Subject {
  2. private IList<Observer> observers = new List<Observer>();
  3. // 增加观察者
  4. public void Attach(Observer observer) {
  5. observers.Add(observer);
  6. }
  7. // 删除观察者
  8. public void Detach(Observer observer) {
  9. observers.Remove(observer);
  10. }
  11. // 通知
  12. public void Notify() {
  13. foreach (Observer o in observers) {
  14. o.Update();
  15. }
  16. }
  17. }
  18. abstract class Observer {
  19. // 更新状态
  20. public abstract void Update();
  21. }
  22. class ConcreteSubject : Subject {
  23. // 具体被观察者的状态
  24. private string subjectState;
  25. public string SubjectState {
  26. get { return subjectState; }
  27. set { subjectState = value; }
  28. }
  29. }
  30. class ConcreteObserver : Observer {
  31. private string name;
  32. private string observerState;
  33. private ConcreteSubject subject;
  34. public ConcreteObserver(ConcreteSubject subject, string name) {
  35. this.name = name;
  36. this.subject = subject;
  37. }
  38. public override void Update() {
  39. observerState = subject.subjectState;
  40. Console.WriteLine("观察者{0}的新状态是{1}", name, observerState);
  41. }
  42. public ConcreteSubject Subject {
  43. get { return subject; }
  44. set { subject = value; }
  45. }
  46. }
  47. static void Main() {
  48. ConcreteObserver s = new ConcreteObserver(); // 创建一个主题
  49. s.Attach(new ConcreteObserver(s, "X"));
  50. s.Attach(new ConcreteObserver(s, "Y"));
  51. s.Attach(new ConcreteObserver(s, "Z"));
  52. s.SubjectState = "ABC"; // 设置状态
  53. s.Notify(); // 通知
  54. }
  55. /*
  56. 结果显示
  57. 观察者X的新状态是ABC
  58. 观察者Y的新状态是ABC
  59. 观察者Z的新状态是ABC
  60. */