很久之前, 自己也曾看过一些设计模式的内容, 最近在做一些程序代码设计的时, 发现忘得差不多了, 很多模式也只是有大致影响, 决定重新将一些常用的模式复习一下. 今天一个模式观察者模式.
观察者模式
观察者模式属于行为模式中的一种; 观察者模式定对象一个一对多的依赖关系, 让多个观察者对象同时监听同一个主题对象, 主题对象在状态发生改变时, 通知所有观察者对象使他们能够更新自己.
上面是观察者模式设计类图
subject: 它是抽象主题的接口, 对象通过此接口将自己注册为观察者, 或将自己从观察中者删除
ConcreteSubject: 一个实现主题接口的具体主题, 除了实现注册和删除的方法外, 它还有一个 change 方法, 用来在状态改变时通知所有观察者
Observer: 观察者接口, 所有具体的观察者都实现此接口
ConcreteObserver: 具体的观察者
- package com.mtx.demo.observer;
- import java.util.ArrayList;
- import java.util.List;
- public abstract class Subject {
- // 保存注册的观察者对象
- private List<Observer> list = new ArrayList<Observer>();
- // 注册观察者对象
- public void attach(Observer observer) {
- list.add(observer);
- System.out.println("添加新的观察者");
- }
- // 删除观察者对象
- public void detach(Observer observer) {
- list.remove(observer);
- System.out.println("删除一个观察者");
- }
- // 通知所有注册的观察者对象
- public void nodifyObservers(String newState) {
- for (Observer observer : list) {
- observer.update(newState);
- }
- }
- }
一个具体主题
- package com.mtx.demo.observer;
- public class ConcreteSubject extends Subject {
- private String state;
- public String getState() {
- return state;
- }
- // 状态发生改变, 通知各个观察者
- public void change(String newState) {
- state = newState;
- this.nodifyObservers(state);
- }
- }
抽象的观察者
- package com.mtx.demo.observer;
- public interface Observer {
- // 更新接口
- public void update(String state);
- }
一个具体观察者
- package com.mtx.demo.observer;
- public class ConcreteObserver implements Observer {
- private String observerState;
- @Override
- public void update(String state) {
- observerState = state;
- System.out.println("观察者状态跟新了:" + observerState);
- }
- }
客户端中, 我们创建一个具体主题对象, 在创建一个观察者对象, 之后将观察注册到主题对象像上, 这样当主题对象的状态改变时, 所有的观察者对象都会收到通知, 改变自己的状态.
- package com.mtx.demo.observer;
- public class Client {
- public static void main(String[] args) {
- // 创建主题对象
- ConcreteSubject subject = new ConcreteSubject();
- // 创建观察者对象
- Observer observer = new ConcreteObserver();
- // 将观察者对象登记到主题对象上
- subject.attach(observer);
- // 改变主题对象的状态
- subject.change("有新的技术博客了");
- }
- }
运行代码结果如下
问题
观察者模式中一对多是如何体现的
主题是一个具有状态的对象, 而多个观察者可以使用这个主题的状态, 多个观察者依赖主题对象来告诉他们这些状态何时改变, 这就产生了一个主题对应多观察者的关系
观察者模式是松如何做到耦合的
主题只知道观察者实现了某一个接口 (Observer 接口), 主题不用知道观察者具体是谁, 做了哪些操作等, 任何时候我们都可以添加新的观察者, 那是因为主题唯一依赖的是一个观察者的 Observer 接口的对象列表, 因此我们可以随时添加观察者, 有新的主题出现时主题代码不用修改.
推模型和拉模型.
推模型: 主题对象向观察者推送主题的详细信息, 不管观察者是否需要, 推送的信息通常是主题对象的全部或部分数据, 刚才上面的例子就是一个推模型.
推模型会是观察者难以复用, 因为每个观察者的 updata 方法的参数可能不同, 数据量非常大的时候推模型不适合
拉模型: 主题对象在通知观察者的时候, 只传递少量信息. 如果观察者需要更具体的信息, 由观察者主动到主题对象中获取, 相当于是观察者从主题对象中拉数据. 一般这种模型的实现中, 会把主题对象自身通过 update() 方法传递给观察者, 这样在观察者需要获取数据的时候, 就可以通过这个引用来获取了.
另外 Java 语言提供的对观察者模式的支持, 在 java.util 包中, 提供了一个 Observable 类以及一个 Observer 接口
优点:
1. 在观察者和被观察者之间建立一个抽象的耦合;
2. 支持广播通信
缺点:
1. 如果一个被观察者对象有很多观察者, 将所有观察者通知到会花费很多时间;
2. 如果在被观察者之间有循环依赖, 被观察者会触发他们之间的循环调用, 导致系统崩溃;
3. 观察者没有相应的方式使其知道所观察的对象时怎么发生变化的.
参考: Head First 设计模式
来源: https://juejin.im/post/5bbde2ece51d450e77630f08