定义

当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。

使用场景

一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

UML

观察者模式 - 图1

角色结构

  • 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
  • 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
  • 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
  • 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。

    优点

    1、观察者和被观察者是抽象耦合的。
    2、建立一套触发机制。

    缺点

    1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
    2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
    3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

    业务场景

    微博粉丝关注偶像,偶像发微博,粉丝都可以收到。

    代码示例

    Idol 偶像接口类

    ```java public interface Idol {

    /**

    • 增加粉丝 *
    • @param fan */ void addFan(Fan fan);

      /**

    • 移除粉丝 *
    • @param fan */ void removeFan(Fan fan);

      /**

    • 发布动态 */ void notify(String msg);

}

  1. <a name="nsmew"></a>
  2. #### Fan 粉丝接口类
  3. ```java
  4. public interface Fan {
  5. /**
  6. * 接受消息
  7. *
  8. * @param msg
  9. */
  10. void receive(String msg);
  11. }

LinYouJia 林宥嘉 - 具体偶像类

  1. public class LinYouJia implements Idol {
  2. private List<Fan> lins = new ArrayList<>();
  3. @Override
  4. public void addFan(Fan fan) {
  5. lins.add(fan);
  6. }
  7. @Override
  8. public void removeFan(Fan fan) {
  9. lins.remove(fan);
  10. }
  11. /**
  12. * 发布动态
  13. */
  14. @Override
  15. public void notify(String msg) {
  16. for (Fan fan : lins) {
  17. //通知每一位粉丝
  18. fan.receive(msg);
  19. }
  20. }
  21. }

ConcreteFan 具体粉丝类

  1. public class ConcreteFan implements Fan {
  2. private String fanName;
  3. public ConcreteFan(String fanName) {
  4. this.fanName = fanName;
  5. }
  6. @Override
  7. public void receive(String msg) {
  8. System.out.println(fanName + "知道了" + msg + "这条消息");
  9. }
  10. }

Client

  1. public class Client {
  2. public static void main(String[] args) {
  3. /**
  4. * 林宥嘉注册账号
  5. */
  6. LinYouJia linYouJia = new LinYouJia();
  7. Fan fan = null;
  8. //增加了很多粉丝
  9. for (int i = 0; i < 10; i++) {
  10. fan = new ConcreteFan("粉丝" + i);
  11. linYouJia.addFan(fan);
  12. }
  13. linYouJia.notify("林宥嘉:我结婚了!");
  14. }
  15. }

输出

  1. 粉丝0知道了林宥嘉:我结婚了!这条消息
  2. 粉丝1知道了林宥嘉:我结婚了!这条消息
  3. 粉丝2知道了林宥嘉:我结婚了!这条消息
  4. 粉丝3知道了林宥嘉:我结婚了!这条消息
  5. 粉丝4知道了林宥嘉:我结婚了!这条消息
  6. 粉丝5知道了林宥嘉:我结婚了!这条消息
  7. 粉丝6知道了林宥嘉:我结婚了!这条消息
  8. 粉丝7知道了林宥嘉:我结婚了!这条消息
  9. 粉丝8知道了林宥嘉:我结婚了!这条消息
  10. 粉丝9知道了林宥嘉:我结婚了!这条消息