20230421 14. 观察者模式 - 摸鱼通知

发布时间 2023-06-19 09:51:25作者: 流星<。)#)))≦

观察者模式 又叫作 发布-订阅(Publish/Subscribe)模式

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

观察者模式

  • Subject类,可翻译为主题或抽象通知者,一般用一个抽象类或者一个接口实现。它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
  • Observer类,抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫作更新接口。抽象观察者一般用一个抽象类或者一个接口实现。更新接口通常包含一个update()方法,这个方法叫作更新方法。
  • ConcreteSubject类,叫作具体主题或具体通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。
  • ConcreteObserver类,具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。具体观察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。

将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便

当一个对象的改变需要同时改变其他对象而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式。

抽象模型有两个方面,其中一方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用

观察者模式所做的工作其实就是在解除耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化

Java已经为观察者模式准备好了相关的接口和抽象类:观察者接口java.util.Observer和通知者类java.util.Observable

代码示例

借助了JDK中的观察者接口java.util.Observer和通知者类java.util.Observable

通知者 Subject

public class Subject extends Observable {
    private String name;

    private String action;

    public Subject(String name) {
        this.name = name;
    }

    public void setAction(String action) {
        this.action = action;
        setChanged();
        notifyObservers();
    }
}


public class Boss extends Subject{
    public Boss(String name) {
        super(name);
    }
}

观察者 Observer

public class StockObserver implements Observer {
    private String name;

    public StockObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(Observable o, Object arg) {
        Subject subject = (Subject) o;
        System.out.println(subject.getName() + ": " + subject.getAction());
        System.out.println(this.name + ", 请关闭股票行情,开始工作");
    }
}


public class NbaObserver implements Observer {
    private String name;

    public NbaObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(Observable o, Object arg) {
        Subject subject = (Subject) o;
        System.out.println(subject.getName() + ": " + subject.getAction());
        System.out.println(this.name + ", 请关闭NBA直播,开始工作");
    }
}

客户端

public class Test {
    public static void main(String[] args) {
        StockObserver stockObserver1 = new StockObserver("张三");
        StockObserver stockObserver2 = new StockObserver("李四");
        NbaObserver nbaObserver1 = new NbaObserver("王五");

        Boss boss = new Boss("boss");

        boss.addObserver(stockObserver1);
        boss.addObserver(stockObserver2);
        boss.addObserver(nbaObserver1);

        boss.setAction("回办公室");

        System.out.println("---------------------------");

        boss.deleteObserver(stockObserver1);

        boss.setAction("检查工作");
    }
}