观察者模式
观察者模式的定义
Observer(观察者)是一种设计模式, 其中, 一个对象(称为 subject) 维持一系列依赖于它的观察者对象, 将有关状态的任何变更自动通知给观察者.
当一个目标(subject)需要告诉观察者发生了什么有趣的事情, 它会向观察者广播一个通知. 当我们不再希望某个特定的观察者获得其注册目标(subject)发出的改变通知时, 该目标可以将它从观察者列表中删除.
“一个或多个观察者对目标的状态感兴趣, 它们通过将自己依附在目标对象上以便注册所感兴趣的内容. 目标状态发生改变并且观察者可能对这些改变感兴趣, 就会发送一个通知消息, 调用每个观察者的更新方法. 当观察者不再对目标状态感兴趣时, 它们可以简单地将自己从中分离.” ———《设计模式: 可复用面向对象软件基础》
观察者模式的理解
从观察者模式的定义中可以对观察者模式有个大体的了解. 观察者模式中有两类, 一类被称为目标(Subject), 一类被称为观察者(Observer). Subject的工作是维护一系列的Observer, 可以对它们进行添加、删除和通知的操作. Observer的工作则是为Subject状态发生变化需要获得通知的对象提供更新接口.
戏说观察者模式
先不管观察者模式是什么, 我们可以试着想想如何从观察者模式的定义去实现这些功能. 下面我们从一个小故事说起.
从前有个人. 凭着天资聪颖再加上闯荡江湖多年, 无论从事什么行业都能称为行业翘楚, 算是有名气的人物.
1 | class Subject {} // 我是有个人. Subject是江湖送我的绰号. |
有一天, 有一个初创公司慕名前来拜访, 探讨如何在现在这个激烈的竞争环境下赢得一席之地.
1 | class Observer {} // 我是一家初创公司, Observer是我公司的名字. |
两人见面直奔主题.
‘你可以派些人来, 我给他们做培训. ’, Subject如此说道. Observer点头同意.
‘可是我如何才能让他们服从并执行呢?’, Subject问到. ‘我们可以向你提供统一的对接方式’, Observer回答到.
‘行, 谁要有兴趣谁就过来吧’
1 | /* update是我们的对接方式, fn是我们的职能. |
为了后续的开展, 夜曉宸也做了准备. 为随后要来的人腾出了空间, 并想好了如何接待每个人.
1 | class Subject { |
不日, Observer派人带着各自本职职务过来了.
1 | const observer1 = new Observer(() => {document.write(`${order}: 我是财务, 我要开始算绩效发工资了<br/>`)); |
既然人来了, 那就接待.
1 | const subject = new Subject(); // 事务繁忙, 派了一个影分身. |
‘既然来到了这个房间, 就要明确一点, 那就是你们得听我指令, 到时我会使用你们公司统一的对接方式’
1 | class Subject { |
‘如果你们不想呆下去了, 可以和我说, 我可以引导你们出去’
1 | class Subject { |
‘现在, 要下达指令了!’
1 | // 省略 |
‘好了, 这些就是我们培训的内容, 就是这么简单’
‘就这么简单?!?, 既然这样, 就送我出去吧, 我不想再呆下去了 ’, observer2说到.
1 | // 省略 |
到此故事告一段落了, Observer模式在线Demo.
再看观察者模式
我们从几段对话中, 稀里糊涂的完成了本文开头观察者模式所定义的那样. 有负责管理一系列依赖的对象, 有提供更新接口的对象. 我们可以看到, 当subject1发出通知时, 每个observe都能去执行. observer们的行为依赖于subject1的. 为什么能够做到这一点, 那是因为observe们的行为作为自身的一部分寄存在了subject1, subject1就可以在需要的时候去自己腾出的小屋子里通知observer们执行.
如果subject1 带着这么一波参加过培训的observer们回去交差, 肯定会被笑话. subject1和observer们的这种协作方式, 被称做观察者模式. 这不过是一个模式, 何时存储何种东西, 何时又去执行存储的东西那才是关键. 如果放到上面的小故事里, 那就是何时需要何种人, 何时开始去做事, 这都需要审时度势. 只有这样公司才能在激烈的竞争环境中赢得一席之地. 只有这样, 观察者模式才能发挥它最大的作用.