观察者模式,事件,监听,触发与推送
理论知识
观察者模式和发布订阅模式其实是一个东西,区别只是在于调度中心。
观察者模式定义了一种一对多的依赖关系,让多个观察者对象(或订阅者对象)同时监听同一个主题。这个主题对象在状态发送变化时,会通知所有的观察者对象(或订阅者对象),使得它们能够自动更新自己。
调度中心的作用之一,每个观察者对象(或者订阅者对象)的行为可能都不一样(方法名不一样),这个时候调度中心就能发挥作用,它提供“事件委托”的功能,主要是提供回调函数的关联。
两个问题
如何实现一个观察者模式
- 非典型的例子,这并不是一个观察者模型 ```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 (
// index1.js import { eventBus } from ‘./index3.jsx’; import React from ‘react’; class ClassB extends React.Component { constructor(props) { super(props); } render(){ return (
为什么观察者模式可以实现数据的传递(状态的自动更新)
<a name="QXYDc"></a>
##
<a name="PZzGr"></a>
## 值的拷贝与值的引用
[https://www.yuque.com/lijunyang/dk90s4/qdxd19#919b86d2](https://www.yuque.com/lijunyang/dk90s4/qdxd19#919b86d2)
<a name="Cq0Bi"></a>
#### 观察者,被观察者(主题)
```javascript
// 观察者
class Observer {
constructor() {
}
update(val) {
}
}
// 观察者列表(目标)
class ObserverList {
constructor() {
this.observerList = []
}
add(observer) {
return this.observerList.push(observer);
}
remove(observer) {
this.observerList = this.observerList.filter(ob => ob !== observer);
}
count() {
return this.observerList.length;
}
get(index) {
return this.observerList(index);
}
}
// 主题(目标)
class Subject {
constructor() {
this.observers = new ObserverList();
}
addObserver(observer) {
this.observers.add(observer);
}
removeObserver(observer) {
this.observers.remove(observer);
}
notify(...args) {
let obCount = this.observers.count();
for (let index = 0; index < obCount; index++) {
this.observers.get(i).update(...args);
}
}
}
const subject = new Subject();
const classA = new Observer();
const classB = new Observer();
Subject.addObserver(classA);
Subject.addObserver(classB);
Subject.notify('发送一个字符串');
有趣的思路
如果将上面的代码与两个问题里的非典型的例子进行组合
// index3.jsx
interface EventType {
eventName: string;
eventFn: (...args: any[]): any;
}
interface EventData {
eventName: string;
paramData: any;
}
class EventMonitor {
listeners = [];
remove = function(eventName) {
const arr = this.listeners.filter((temp) => {
return temp.eventName !== eventName;
});
this.listeners = arr;
}
trigger = function(eventName, param) {
this.listeners.forEach((item) => {
if (eventName === item.eventName) {
item.fn(param);
}
})
}
on = function(eventName, fn) {
this.listeners.push({
eventName,
fn
});
}
}
class EventBus {
const listeners: EventType[] = [];
// 添加一个事件(主题)
addEvent(event: EventType){}
// 移除一个事件(主题)
removeEvent(eventName){}
// 触发一个事件(通知,主题发生了变化)
trigger(eventName){}
}
调度中心
class PubSub {
constructor() {
this.subscribers = {}
}
subscribe(type, fn) {
if (!Object.prototype.hasOwnProperty.call(this.subscribers, type)) {
this.subscribers[type] = [];
}
this.subscribers[type].push(fn);
}
unsubscribe(type, fn) {
let listeners = this.subscribers[type];
if (!listeners || !listeners.length) return;
this.subscribers[type] = listeners.filter(v => v !== fn);
}
publish(type, ...args) {
let listeners = this.subscribers[type];
if (!listeners || !listeners.length) return;
listeners.forEach(fn => fn(...args));
}
}
let ob = new PubSub();
ob.subscribe('add', (val) => console.log(val));
ob.publish('add', 1);
一个应用场景
abstract class Subject {
private IList<Observer> observers = new List<Observer>();
// 增加观察者
public void Attach(Observer observer) {
observers.Add(observer);
}
// 删除观察者
public void Detach(Observer observer) {
observers.Remove(observer);
}
// 通知
public void Notify() {
foreach (Observer o in observers) {
o.Update();
}
}
}
abstract class Observer {
// 更新状态
public abstract void Update();
}
class ConcreteSubject : Subject {
// 具体被观察者的状态
private string subjectState;
public string SubjectState {
get { return subjectState; }
set { subjectState = value; }
}
}
class ConcreteObserver : Observer {
private string name;
private string observerState;
private ConcreteSubject subject;
public ConcreteObserver(ConcreteSubject subject, string name) {
this.name = name;
this.subject = subject;
}
public override void Update() {
observerState = subject.subjectState;
Console.WriteLine("观察者{0}的新状态是{1}", name, observerState);
}
public ConcreteSubject Subject {
get { return subject; }
set { subject = value; }
}
}
static void Main() {
ConcreteObserver s = new ConcreteObserver(); // 创建一个主题
s.Attach(new ConcreteObserver(s, "X"));
s.Attach(new ConcreteObserver(s, "Y"));
s.Attach(new ConcreteObserver(s, "Z"));
s.SubjectState = "ABC"; // 设置状态
s.Notify(); // 通知
}
/*
结果显示
观察者X的新状态是ABC
观察者Y的新状态是ABC
观察者Z的新状态是ABC
*/