img

什么是观察者模式

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

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

观察者角色

  • 抽象被观察者角色:定义了动态增加、删除以及通知观察者对象的方法,职责就是管理和通知观察者。持有观察者对象的集合。
  • 具体被观察者角色:一般继承抽象被观察者,实现自己本身的业务逻辑,当状态发生改变时发起通知。
  • 抽象观察者角色:提供一个接口,定义了观察者收到通知时更新自己的方法。
  • 具体观察者角色:实现抽象观察者接口,处理不同具体观察者的不同业务逻辑。

优缺点

优点

  • 观察者和被观察者是抽象耦合的。
  • 建立一套触发机制。
  • 对象之间的保持高度的协作。当被观察者发生变化时,所有被观察者都会通知到,然后做出相应的动作。

缺点

  • 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
  • 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
  • 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
  • 如果观察者太多,被观察者通知观察者消耗的时间很多,影响系统的性能。
  • 当观察者集合中的某一观察者错误时就会导致系统卡壳,因此一般会采用异步方式。

适用场景

  • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
  • 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
  • 一个对象必须通知其他对象,而并不知道这些对象是谁。
  • 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

实现

灰太狼具有被观察者属性,喜洋洋这些羊咩咩一直都在观察者灰太狼,所以羊咩咩们是观察者。OK,角色确定了,看看具体是怎么实现的…

抽象被观察者

public abstract class Subject {

    /**
     * 观察者对象的集合
     */
    private List<Observer> observerList = new ArrayList<>();

    /**
     * 登记观察者
     *
     * @param observer
     */
    public void attach(Observer observer) {
        observerList.add(observer);
        System.out.println("增加了观察者:" + observer.getName());
    }

    /**
     * 删除观察者
     *
     * @param observer
     */
    public void dettach(Observer observer) {
        observerList.remove(observer);
        System.out.println("删除了观察者:" + observer.getName());
    }

    /**
     * 通知所有观察者
     */
    public void notifyObserver() {
        for (Observer observer : observerList) {
            observer.update("灰太狼要搞事情了");
        }
    }

}

创建被观察者对象

灰太狼是具体被观察者,继承抽象被观察者

public class Wolf extends Subject {
    public void invade(){
        System.out.println("灰太狼:我要搞事情了");
        // 通知所有观察者
        notifyObserver();
    }

}

抽象观察者

public interface Observer {

    String getName();

    /**
     * 通知更新方法
     *
     * @param msg
     */
    public void update(String msg);

}

创建观察者对象

喜羊羊是具体观察者

public class PleasantSheep implements Observer{

    @Override
    public String getName() {
        return "喜羊羊";
    }

    /**
     * 具体业务逻辑
     */
    @Override
    public void update(String msg) {
        System.out.println("喜羊羊收到通知:" + msg);
    }

}

测试

接下来看客户端如何把观察者模式跑起来

public class Client {

    public static void main(String[] args) {
        // 灰太狼--被观察者
        Wolf wolf = new Wolf();
        // 喜羊羊--观察者
        Observer pleasantSheep = new PleasantSheep();
        // 登记观察者
        wolf.attach(pleasantSheep);
        // 灰太狼入侵
        wolf.invade();
    }

}

输出

增加了观察者:喜羊羊
灰太狼:我要搞事情了
喜羊羊收到通知:灰太狼要搞事情了

总结

在Java中已经提供了Observable类以及一个Observer接口,也就是说Java已经实现了观察者模式的定义