定义

观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

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

结构

一个软件系统里面包含了各种对象,就像一片欣欣向荣的森林充满了各种生物一样。在一片森林中,各种生物彼此依赖和约束,形成一个个生物链。一种生物的状态变化会造成其他一些生物的相应行动,每一个生物都处于别的生物的互动之中。

一个软件系统常常要求在某一个对象的状态发生变化的时候,某些其他的对象做出相应的改变。做到这一点的设计方案有很多,但是为了使系统能够易于复用,应该选择低耦合度的设计方案。减少对象之间的耦合有利于系统的复用,但是同时设计师需要使这些低耦合度的对象之间能够维持行动的协调一致,保证高度的协作。观察者模式是满足这一要求的各种设计方案中最重要的一种。

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

  • 抽象主题(Subject)角色:抽象主题角色把所有对观察者对象的引用保存在一个聚集(比如ArrayList对象)里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,抽象主题角色又叫做抽象被观察者(Observable)角色。
  • 具体主题(ConcreteSubject)角色:将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者(Concrete Observable)角色。
  • 抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口。
  • 具体观察者(ConcreteObserver)角色:存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态 像协调。如果需要,具体观察者角色可以保持一个指向具体主题对象的引用。

实现

//抽象主题角色类
public abstract class Subject {/*** 用来保存注册的观察者对象*/private    List<Observer> list = new ArrayList<Observer>();/*** 注册观察者对象* @param observer    观察者对象*/public void attach(Observer observer){list.add(observer);System.out.println("Attached an observer");}/*** 删除观察者对象* @param observer    观察者对象*/public void detach(Observer observer){list.remove(observer);}/*** 通知所有注册的观察者对象*/public void nodifyObservers(String newState){for(Observer observer : list){observer.update(newState);}}
}
//具体主题角色类
public class ConcreteSubject extends Subject{private String state;public String getState() {return state;}public void change(String newState){state = newState;System.out.println("主题状态为:" + state);//状态发生改变,通知各个观察者this.nodifyObservers(state);}
}
//抽象观察者角色类
public interface Observer {/*** 更新接口* @param state    更新的状态*/public void update(String state);
}
//具体观察者角色类
public class ConcreteObserver implements Observer {//观察者的状态private String observerState;@Overridepublic void update(String state) {/*** 更新观察者的状态,使其与目标的状态保持一致*/observerState = state;System.out.println("状态为:"+observerState);}
}
//客户端类
public class Client {public static void main(String[] args) {//创建主题对象ConcreteSubject subject = new ConcreteSubject();//创建观察者对象Observer observer = new ConcreteObserver();//将观察者对象登记到主题对象上
        subject.attach(observer);//改变主题对象的状态subject.change("new state");}
}

在运行时,这个客户端首先创建了具体主题类的实例,以及一个观察者对象。然后,它调用主题对象的attach()方法,将这个观察者对象向主题对象登记,也就是将它加入到主题对象的聚集中去。客户端调用主题的change()方法,改变了主题对象的内部状态。主题对象在状态发生变化时,调用超类的notifyObservers()方法,通知所有登记过的观察者对象。

推模型和拉模型

在观察者模式中,又分为推模型和拉模型两种方式。

推模型:主题对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。

拉模型:主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取,相当于是观察者从主题对象中拉数据。一般这种模型的实现中,会把主题对象自身通过update()方法传递给观察者,这样在观察者需要获取数据的时候,就可以通过这个引用来获取了。

根据上面的描述,前面的例子就是典型的推模型,下面给出一个拉模型的实例。

拉模型的抽象观察者类:拉模型通常都是把主题对象当做参数传递。

public interface Observer {/*** 更新接口* @param subject 传入主题对象,方面获取相应的主题对象的状态*/public void update(Subject subject);
}
//拉模型的具体观察者类
public class ConcreteObserver implements Observer {//观察者的状态private String observerState;@Overridepublic void update(Subject subject) {/*** 更新观察者的状态,使其与目标的状态保持一致*/observerState = ((ConcreteSubject)subject).getState();System.out.println("观察者状态为:"+observerState);}}
//拉模型的抽象主题类,拉模型的抽象主题类主要的改变是nodifyObservers()方法。在循环通知观察者的时候,也就是循环调用观察者的update()方法的时候,传入的参数不同了。
public abstract class Subject {/*** 用来保存注册的观察者对象*/private    List<Observer> list = new ArrayList<Observer>();/*** 注册观察者对象* @param observer    观察者对象*/public void attach(Observer observer){list.add(observer);System.out.println("Attached an observer");}/*** 删除观察者对象* @param observer    观察者对象*/public void detach(Observer observer){list.remove(observer);}/*** 通知所有注册的观察者对象*/public void nodifyObservers(){for(Observer observer : list){observer.update(this);}}
}
//拉模型的具体主题类,跟推模型相比,有一点变化,就是调用通知观察者的方法的时候,不需要传入参数了。
public class ConcreteSubject extends Subject{private String state;public String getState() {return state;}public void change(String newState){state = newState;System.out.println("主题状态为:" + state);//状态发生改变,通知各个观察者this.nodifyObservers();}
}

两种模式的比较

推模型是假定主题对象知道观察者需要的数据;而拉模型是主题对象不知道观察者具体需要什么数据,没有办法的情况下,干脆把自身传递给观察者,让观察者自己去按需要取值。

推模型可能会使得观察者对象难以复用,因为观察者的update()方法是按需要定义的参数,可能无法兼顾没有考虑到的使用情况。这就意味着出现新情况的时候,就可能提供新的update()方法,或者是干脆重新实现观察者;而拉模型就不会造成这样的情况,因为拉模型下,update()方法的参数是主题对象本身,这基本上是主题对象能传递的最大数据集合了,基本上可以适应各种情况的需要。

JAVA提供的对观察者模式的支持

在JAVA语言的java.util库里面,提供了一个Observable类以及一个Observer接口,构成JAVA语言对观察者模式的支持。

Observer接口

这个接口只定义了一个方法,即update()方法,当被观察者对象的状态发生变化时,被观察者对象的notifyObservers()方法就会调用这一方法。

public interface Observer {void update(Observable o, Object arg);
}

Observable类

被观察者类都是java.util.Observable类的子类。java.util.Observable提供公开的方法支持观察者对象,这些方法中有两个对Observable的子类非常重要:一个是setChanged(),另一个是notifyObservers()。第一方法setChanged()被调用之后会设置一个内部标记变量,代表被观察者对象的状态发生了变化。第二个是notifyObservers(),这个方法被调用时,会调用所有登记过的观察者对象的update()方法,使这些观察者对象可以更新自己。

public class Observable {private boolean changed = false;private Vector obs;/** Construct an Observable with zero Observers. */public Observable() {obs = new Vector();}/*** 将一个观察者添加到观察者聚集上面*/public synchronized void addObserver(Observer o) {if (o == null)throw new NullPointerException();if (!obs.contains(o)) {obs.addElement(o);}}/*** 将一个观察者从观察者聚集上删除*/public synchronized void deleteObserver(Observer o) {obs.removeElement(o);}public void notifyObservers() {notifyObservers(null);}/*** 如果本对象有变化(那时hasChanged 方法会返回true)* 调用本方法通知所有登记的观察者,即调用它们的update()方法* 传入this和arg作为参数*/public void notifyObservers(Object arg) {Object[] arrLocal;synchronized (this) {if (!changed)return;arrLocal = obs.toArray();clearChanged();}for (int i = arrLocal.length-1; i>=0; i--)((Observer)arrLocal[i]).update(this, arg);}/*** 将观察者聚集清空*/public synchronized void deleteObservers() {obs.removeAllElements();}/*** 将“已变化”设置为true*/protected synchronized void setChanged() {changed = true;}/*** 将“已变化”重置为false*/protected synchronized void clearChanged() {changed = false;}/*** 检测本对象是否已变化*/public synchronized boolean hasChanged() {return changed;}/*** Returns the number of observers of this <tt>Observable</tt> object.** @return  the number of observers of this object.*/public synchronized int countObservers() {return obs.size();}
}

这个类代表一个被观察者对象,有时称之为主题对象。一个被观察者对象可以有数个观察者对象,每个观察者对象都是实现Observer接口的对象。在被观察者发生变化时,会调用Observable的notifyObservers()方法,此方法调用所有的具体观察者的update()方法,从而使所有的观察者都被通知更新自己。

怎样使用JAVA对观察者模式的支持

被观察对象叫做Watched;而观察者对象叫做Watcher。Watched对象继承自java.util.Observable类;而Watcher对象实现了java.util.Observer接口。另外有一个Test类扮演客户端角色。

//被观察者Watched类
public class Watched extends Observable{private String data = "";public String getData() {return data;}public void setData(String data) {if(!this.data.equals(data)){this.data = data;setChanged();}notifyObservers();}
}
//观察者类
public class Watcher implements Observer{    public Watcher(Observable o){o.addObserver(this);}   @Overridepublic void update(Observable o, Object arg) {     System.out.println("状态发生改变:" + ((Watched)o).getData());}
}
//测试类
public class Test {public static void main(String[] args) {//创建被观察者对象Watched watched = new Watched();//创建观察者对象,并将被观察者对象登记Observer watcher = new Watcher(watched);//给被观察者状态赋值watched.setData("start");watched.setData("run");watched.setData("stop");}
}

Test对象首先创建了Watched和Watcher对象。在创建Watcher对象时,将Watched对象作为参数传入;然后Test对象调用Watched对象的setData()方法,触发Watched对象的内部状态变化;Watched对象进而通知实现登记过的Watcher对象,也就是调用它的update()方法。

转载于:https://www.cnblogs.com/wade-luffy/p/5812563.html

观察者模式-对象行为型相关推荐

  1. 设计模式 ( 十六 ) 观察者模式Observer(对象行为型)

    设计模式 ( 十五 ) 观察者模式Observer(对象行为型) 1.概述 一些面向对象的编程方式,提供了一种构建对象间复杂网络互连的能力.当对象们连接在一起时,它们就可以相互提供服务和信息. 通常来 ...

  2. Typescript玩转设计模式 之 对象行为型模式(上)

    作者简介 joey 蚂蚁金服·数据体验技术团队 继前面几篇设计模式文章之后,这篇介绍5个对象行为型设计模式. Chain of Responsibility(职责链) 意图 使多个对象都有机会处理请求 ...

  3. 设计模式-对象行为型模式

    [对象行为型模式]涉及到算法和对象间职责的分配,描述了对象和类的模式,以及它们之间的通信模式. 用来对类或对象怎样交互和怎样分配职责进行描述 1.  策略模式(strategy)           ...

  4. 设计模式 ( 十八 ) 策略模式Strategy(对象行为型)

    设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述 在软件开发中也经常遇到类似的情况,实现某一个功能有多种算法或者策略,我们能够依据环境或者条件的不同选择不同的算法或者策略来完毕 ...

  5. 2018.3.31 设计模式之生成器模式详解及例子(对象创建型模式)

    设计模式之生成器模式(对象创建型模式) 1.定义/概念 将一个复杂对象的创建和它的表示分离,使得同样的创建过程可以有不同的表示. 2.生成模式角色 Builder: 生成器接口,定义创建一个Produ ...

  6. 设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型)

    设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型) 1.概述 类中的面向对象编程封装应用逻辑.类,就是实例化的对象,每个单独的对象都有一个特定的身份和状态.单独的对象是一种组织代码的有用 ...

  7. Visitor(访问者)--对象行为型模式

    Visitor(访问者)–对象行为型模式 一.意图 表示一个作用于某个对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作. 二.动机 1.在软件构建过程中,由于需 ...

  8. Strategy(策略)--对象行为型模式

    Strategy(策略)–对象行为型模式 一.意图 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换.本模式使得算法可独立于使用它的客户而变化. 二.动机 1.在软件构建过程中,某些对象使 ...

  9. State(状态)--对象行为型模式

    State(状态)–对象行为型模式 一.意图 允许一个对象在其内部状态改变时改变它的行为.对象看起来似乎修改了它的类. 二.动机 1.在软件构建过程中,某些对象的状态如果改变,其行为也会随之而发生变化 ...

最新文章

  1. getTasksWithCompletionHandler的用法
  2. Windows 8.1 应用再出发 - 创建我的第一个应用
  3. Thinkpad SL400 issue
  4. Pytorch gpu加速方法
  5. 自己动手:修改crx文件制作自己的Chrome Apps
  6. 无符号数的减法_C++核心准则ES.107:不要使用无符号数下标,使用gsl::index更好
  7. 使用Docker容器的十大误区
  8. python同步两张数据表_Python 如何实现数据库表结构同步
  9. python语言中有3种表示字符串的方式、单引号和_Python中三种类型的引号(单引号、双引号、三引号)...
  10. php mian函数,电脑main什么意思
  11. mysql8 修改密码_MySQL 8.0 解决:ERROR 2002、ERROR 1045 登陆问题
  12. 专注技术,回归本质,这就是太平洋未来科技的创新之处...
  13. 【知识图谱系列】多关系异质图神经网络CompGCN
  14. pdf覆盖图片 Java_Java 添加、替换、删除PDF中的图片
  15. 禁止Edge浏览器自动更新的办法
  16. 如何在C++中删除文件
  17. 建立桌面文件管理格子_win10如何创建桌面格子_win10怎么建立桌面文件管理格子...
  18. 简易记账开发笔记之Fragment(后续)
  19. 如何用PS将gif图背景变透明
  20. 诺基亚 android系统升级,诺基亚在中国发布的智能手机都已升级至Android 9.0系统...

热门文章

  1. Linux如何切换图形界面和命令行界面
  2. Thread.sleep()和TimeUnit.SECONDS.sleep()的区别与联系
  3. 韭菜财经大数据:《2019年内容创业市场报告》
  4. 初识Scrapy,在充满爬虫的世界里做一个好公民
  5. CKeditor的几种配置方式
  6. LVS学习笔记--DR模式部署
  7. OpenLDAP的安装和配置(含TLS和复制)
  8. NAT负载均衡_ftp
  9. 奇文:金庸小说中的第一高手是谁?
  10. 乌托邦式的经理人日记——小的奖励激发员工热情