设计模式 —— 观察者模式

简介

观察者模式(Observer Pattern)属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知全部的观察者对象,使他们可以自动更新。观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。java

观察者模式的推拉方式

  • 推方式:

主题对象向观察者推送主题的详细信息,无论观察者是否须要,推送的信息一般是主题对象的所有或部分数据。设计模式

  • 拉方式:

主题对象在通知观察者的时候,只传递少许信息。若是观察者须要更具体的信息,由观察者主动到主题对象中获取,至关因而观察者从主题对象中拉数据。通常这种模型的实现中,会把主题对象自身经过update()方法传递给观察者,这样在观察者须要获取数据的时候,就能够经过这个引用来获取了。异步

实例

观察者模式所涉及的角色有:ide

  1. 抽象主题角色(Subject):抽象主题角色把全部对观察者对象的引用保存在一个汇集(好比ArrayList对象)里,每一个主题均可以有任何数量的观察者。抽象主题提供一个接口,能够增长和删除观察者对象,抽象主题角色又叫作抽象被观察者(Observable)角色;this

  2. 具体主题角色(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给全部登记过的观察者发出通知。具体主题角色又叫作具体被观察者(Concrete Observable)角色;spa

  3. 抽象观察者角色(Observer):为全部的具体观察者定义一个接口,在获得主题的通知时更新本身,这个接口叫作更新接口;设计

  4. 具体观察者角色(ConcreteObserver):存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使自己的状态与主题的状态像协调。若是须要,具体观察者角色能够保持一个指向具体主题对象的引用。code

  • 推方式:
// 抽象观察者角色类
public interface Observer {
    void update(String message);
}
// 抽象主题角色类
public abstract class AbstractSubject {
    private List<Observer> list = new ArrayList<>();

    public void attach(Observer observer) {
        list.add(observer);
    }

    public void detach(Observer observer) {
        list.remove(observer);
    }

    public void notifyObserver(String message) {
        for (Observer observer : list) {
            observer.update(message);
        }
    }
}

// 具体观察者角色类
public class WxUserObserver implements Observer {

    private String name;

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

    @Override
    public void update(String message) {
        System.out.println(name + "收到推送消息:" + message);
    }

}

// 具体主题角色类
public class WxSubject extends AbstractSubject {

    public void change(String message) {
        this.notifyObserver(message);
    }
}

// 客户端
public class Client {
    @Test
    public void test() {
        WxSubject subject = new WxSubject();

        final WxUserObserver zs = new WxUserObserver("张三");
        final WxUserObserver ls = new WxUserObserver("李四");
        final WxUserObserver ww = new WxUserObserver("王五");

        // 初始化三个关注用户
        subject.attach(zs);
        subject.attach(ls);
        subject.attach(ww);

        subject.change("开始推送消息1");
        // 张三取消关注
        subject.detach(zs);
        subject.change("开始推送消息2");
    }
}
复制代码
张三收到推送消息:开始推送消息1
李四收到推送消息:开始推送消息1
王五收到推送消息:开始推送消息1
李四收到推送消息:开始推送消息2
王五收到推送消息:开始推送消息2
复制代码
  • 拉方式:
// 抽象观察者角色类
public interface Observer {
    void update(AbstractSubject subject);
}

// 抽象主题角色类
public abstract class AbstractSubject {
    private List<Observer> list = new ArrayList<>();

    public void attach(Observer observer) {
        list.add(observer);
    }

    public void detach(Observer observer) {
        list.remove(observer);
    }

    public void notifyObserver() {
        for (Observer observer : list) {
            observer.update(this);
        }
    }
}

// 具体观察者角色类
public class WxUserObserver implements Observer {

    private String name;

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

    @Override
    public void update(String message) {
        System.out.println(name + "收到推送消息:" + message);
    }

}

// 具体主题角色类
public class WxSubject extends AbstractSubject {

    private String state;


    public String getState() {
        return state;
    }


    public void change(String state) {
        this.state = state;
        this.notifyObserver();
    }
}

// 客户端
public class Client {
    @Test
    public void test() {
        WxSubject subject = new WxSubject();

        final WxUserObserver zs = new WxUserObserver("张三");
        final WxUserObserver ls = new WxUserObserver("李四");
        final WxUserObserver ww = new WxUserObserver("王五");

        // 初始化三个关注用户
        subject.attach(zs);
        subject.attach(ls);
        subject.attach(ww);
        subject.change("State");

        // 李四取消关注
        subject.detach(ls);
        subject.change("new State");
    }
}
复制代码
张三状态更新为:State
李四状态更新为:State
王五状态更新为:State
张三状态更新为:new State
王五状态更新为:new State
复制代码
  • JDK 实现:

Java语言的java.util库里面,提供了一个Observable类以及一个Observer接口,构成了Java语言对观察者模式的支持。 Observer接口只定义了一个update()方法,当被观察者对象的状态发生变化时,被观察者对象的notifyObservers()方法就会调用这一方法。 Observable类是被观察者类的基类。java.util.Observable提供公开的方法支持观察者对象,这些方法中有两个对Observable的子类很是重要:一个是setChanged(),另外一个是notifyObservers()。第一方法setChanged()被调用以后会设置一个内部标记变量,表明被观察者对象的状态发生了变化。第二个是notifyObservers(),这个方法被调用时,会调用全部登记过的观察者对象的update()方法,使这些观察者对象能够更新本身。cdn

// 观察者
public class WxUserObserver implements Observer {

    private String name;

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

    @Override
    public void update(Observable o, Object arg) {
        System.out.println(name + "状态更新为:" + ((WxObservable) o).getState());
    }
}

// 被观察者
public class WxObservable extends Observable {

    private String state;


    public String getState() {
        return state;
    }

    public void change(String state) {
        this.state = state;
        this.setChanged(); // 设置一个内部标记变量
        this.notifyObservers(); // 调用全部登记过的观察者对象的update()方法
    }
}

public class Client {
    @Test
    public void test() {
        WxObservable observable = new WxObservable();

        final WxUserObserver zs = new WxUserObserver("张三");
        final WxUserObserver ls = new WxUserObserver("李四");
        final WxUserObserver ww = new WxUserObserver("王五");

        observable.addObserver(zs);
        observable.addObserver(ls);
        observable.addObserver(ww);
        observable.change("State");

        observable.deleteObserver(ls);
        observable.change("new State");
    }
}
复制代码
张三状态更新为:State
李四状态更新为:State
王五状态更新为:State
张三状态更新为:new State
王五状态更新为:new State
复制代码

用JDK提供的这种方式能很好方便的实现,推方式和拉方式的设计模式。server

类图

推方式:

推方式

拉方式:

拉方式

JDK实现:

JDK实现

优势

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

缺点

  1. 若是一个被观察者对象有不少的直接和间接的观察者的话,将全部的观察者都通知到会花费不少时间;

  2. 若是在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能致使系统崩溃;

  3. 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

适用场景

  1. 一个抽象模型有两个方面,其中一个方面依赖于另外一个方面。将这些方面封装在独立的对象中使它们能够各自独立地改变和复用;

  2. 一个对象的改变将致使其余一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,能够下降对象之间的耦合度;

  3. 一个对象必须通知其余对象,而并不知道这些对象是谁;

  4. 须要在系统中建立一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可使用观察者模式建立一种链式触发机制。

总结

观察者模式用于创建一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其余对象,其余对象将相应做出反应。在 Java 中已经对观察者模式的支持类 java.util.Observerjava.util.Observable,不须要咱们本身实现。使用中注意避免循环引用。若是顺序执行,某一观察者错误会致使系统卡壳,通常采用异步方式。

相关文章
相关标签/搜索