设计模式--观察者模式(详解)

来源:互联网 发布:dd linux sync 编辑:程序博客网 时间:2024/05/21 17:57

java设计模式--观察者模式


一个贴切又通俗的例子让你明白什么是观察者模式,同时还告诉你java内置的观察者。

1. 概述

  观察者模式定义了对象之间的一对多的依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。有时被称作发布/订阅模式,

可借助下图理解下定义


2. 解决的问题

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

3. 模式中的角色

   抽象主题(Subject):它把所有观察者对象的引用保存到一个集合里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。

  具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。

  抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。

  具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。

4. 模式解读

    观察者模式类图

那么,下面,用一个生活中很贴切的例子来解释什么是观察者模式----公众号订阅

假设有一个主题公众号叫“笑话十则”,有三个用户(当然可以更多)订阅了此公众号,那么我们众所周知的是,当笑话每日一旦有更新时,就会通知它的每一个订阅者。下面是java代码:

import java.util.ArrayList;import java.util.List;/** * 观察者模式 * @Author 先 * @ClassName Test_Observer.java * @Time 2017年3月13日 下午8:19:26 */public class Test_Observer {public static void main(String[] args) {//先有公众号Subject s = new CommonNumber();//有几个人订阅该公众号Observer zhang = new Order("张三",s);Observer li = new Order("李四",s);Observer wang = new Order("王五",s);//公众号的内容有更新,提醒每一个订阅者s.notifyOrder("新-笑话十则");}}/** * 抽象主题--公众号接口,任何实现该接口的,都是一个具体的公众号 * @Author 先 * @ClassName Test_Observer.java * @Time 2017年3月13日 下午8:25:08 */interface Subject{//通知订阅者abstract void notifyOrder(String data);//注册订阅者abstract void addOrder(Observer o);//移除订阅者abstract void removeOrder(Observer o);}/** * 抽象观察者--订阅者,只要实现了该接口的,都是一个具体的订阅者 * @Author 先 * @ClassName Test_Observer.java * @Time 2017年3月13日 下午8:26:17 */interface Observer{//用来自动更新关注的公众号的信息abstract void update(String data);}/** * 具体主题--公众号 * @Author 先 * @ClassName Test_Observer.java * @Time 2017年3月13日 下午8:28:40 */class CommonNumber implements Subject{//将订阅了本公众号的客户放到一个集合里private List<Observer> list = new ArrayList<Observer>();@Overridepublic void notifyOrder(String data) {for (Observer observer : list) {observer.update(data);}}@Overridepublic void addOrder(Observer o) {list.add(o);}@Overridepublic void removeOrder(Observer o) {list.remove(o);}}/** * 具体观察者--公众号的订阅者A * @Author 先 * @ClassName Test_Observer.java * @Time 2017年3月13日 下午8:39:16 */class Order implements Observer{private String userName;public Order(String userName,Subject s){this.userName = userName;//在构造方法里订阅s.addOrder(this);}@Overridepublic void update(String data) {System.out.println("我是订阅者" + userName + ",我收到更新信息了!--" + data);}}
运行结果


而java的jdk中,内部也有自己观察者模式接口与类,看下例(你会发现,笔者根本就没有写什么具体代码,就能够通知观察者了,这就是因为java内部有观察者模式):

import java.util.Observable;import java.util.Observer;/** * java内置观察者模式 * @Author 先 * @ClassName Test2_Observer.java * @Time 2017年3月13日 下午8:56:53 */public class Test2_Observer {public static void main(String[] args) {CommonNumberA subject1 = new CommonNumberA();CommonNumberB subject2 = new CommonNumberB();Observer xiaoming = new Order("小明");Observer dahong = new Order("大红");subject1.addObserver(xiaoming);subject2.addObserver(dahong);subject1.myNotify();subject2.myNotify();}}/** * java有内置的观察者模式(主题) * 继承JDK中的java.util.Observable * @Author 先 * @ClassName Test2_Observer.java * @Time 2017年3月13日 下午9:35:53 */class CommonNumberA extends Observable{//直接继承java内部的Observable类--主题对象public void myNotify(){setChanged();notifyObservers("音乐主题");}}class CommonNumberB extends Observable{public void myNotify(){setChanged();notifyObservers("视频主题");}}/** * 具体观察者 * @Author 先 * @ClassName Test2_Observer.java * @Time 2017年3月21日 下午9:13:37 */class Order implements Observer{//直接实现java内部的Observer接口--观察者对象private String name;public Order(String name){this.name = name;}@Overridepublic void update(Observable o, Object arg) {System.out.println(name + "订阅的是" + arg);}}
分析:

首先需要告诉读者,java内置的观察者模式进行更新通知时,需要执行两个步骤

1、先调用setChanged()方法,标记状态已经改变的事实;

2、然后调用两种notifyObservers()方法中的一个,用法见下图

另外需要注意的是

jdk观察者模式部分源代码如下,读者可在自己的开发环境中查看更详细的源码



5. 模式总结

   优点

     观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。

   缺点

     依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。

  适用场景

    5.3.1 当一个对象的改变需要给变其它对象时,而且它不知道具体有多少个对象有待改变时。

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

希望对读者有帮助!转载请注明出处!


1 0
原创粉丝点击