设计模式之-观察者模式的使用

162 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天。

定义

在软件系统中,如果一个对象的状态发生改变,某些与他相关的对象也要随之做出相应的变化。观察者模式包含观察目标(被观察者)和观察者两类对象,一个目标可以有任意数目的与之相依赖的观察者,一旦观察目标的状态发生变化,所有的观察者都将得到通知(定义对象之间一种一对多的关系)。

代码演示

1、被观察者(Subject)

import java.util.Vector;
// 用Vector是因为多线程时Vector是线程安全的,而List不是
public abstract class Subject {
    private Vector<Observer> obs = new Vector<>();

    public void addObserver(Observer observer) {
        this.obs.add(observer);
    }

    public void delObserver(Observer observer) {
        this.obs.remove(observer);
    }

    protected void notifyObserver(){
        for (Observer observer:obs) {
            observer.update();
        }
    }
    public abstract void doSomething();
}

2、(具体目标)ConcreteSubject,是目标类的子类,通常包含经常发生改变的数据。

public class ConcreteSubject extends Subject{
    /**
     * 具体的被观察者
     */
    public void doSomething(){
        System.out.println("被观察者事件发生改变");
        this.notifyObserver();
    }
}

3、(观察者)Obeserver,将针对观察目标的改变做出反应,一般是接口,声明了更新数据的方法update(),也叫抽象观察者。

public interface Observer {
    void update();
}

4、具体观察者(ConcreteObserver),在具体观察者中维护一个指向目标对象的引用。存储具体观察者的一些状态。

public class ConcreteObserver1 implements Observer{
    @Override
    public void update() {
        System.out.println("观察者1收到信息处理");
    }
}

public class ConcreteObserver2 implements Observer{
    @Override
    public void update() {
        System.out.println("观察者2收到信息并处理");
    }
}

处理

public class Client {
    public static void main(String[] args) {
        Subject subject = new ConcreteSubject();
        subject.addObserver(new ConcreteObserver1());
        subject.addObserver(new ConcreteObserver2());
        subject.doSomething();
    }
}

输出

被观察者事件发生改变
观察者1收到信息处理
观察者2收到信息并处理

使用场景举例

  • 微信公众号的消息通知,公众号就是被观察者,用户就是观察者,当公众号有新消息所有用户都能收到。
  • MVC中的模型与视图,模型有新消息产生,视图也能及时感应到。

优缺点

优点

  • 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系;
  • 目标与观察者之间建立了一套触发机制;
  • 支持广播通信;
  • 符合“开闭原则”(开闭原则是指:模块和函数应该对扩展开放,对修改关闭);

缺点

  • 当观察者对象很多时,通知的发布会话费很多时间,影响程序的效率;
  • 目标域观察者之间的依赖关系没有完全解除,可能出现循环引用;

用途

  • 当抽象个体有两个互相依赖的层面时。封装这些层面在单独的对象内将可允许程序员单独地去变更与重复使用这些对象,而不会产生两者之间交互的问题。
  • 当其中一个对象的变更会影响其他对象,却又不知道多少对象必须被同时变更时。
  • 当对象应该有能力通知其他对象,又不应该知道其他对象的实做细节时。