文档章节

观察者(Observer)模式

叶知秋
 叶知秋
发布于 2013/08/15 22:26
字数 1671
阅读 57
收藏 0

       观察者模式是对象的行为模式,又叫发布-订阅模式、模型-视图模式、源-监听模式、或从属者模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有的观察者对象,使它们能够自己更新自己。
       一个软件系统常常要求在某一个对象的状态发生变化的时候,某些其他的对象做出相应的改变。能做到这一点的设计方案很多,但是为了使系统易于复用,应该选用低耦合度的设计方案。减少对象之间的耦合有助于系统的复用,但是同时设计师需要使这些低耦合度的对象之间能够维持行为的协调一致,保证高度的协作。观测者模式是满足这一要求的各种设计方案中最重要的一种。
     
观察者模式的结构
      
下图是一个简单的示意性实现类图:
                                         
           观察者模式的静态结构可以从类图中看出,在这个观察者模式的实现中,有以下角色:
      (1)抽象主题(Subject)角色:主题角色把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,主题角色又叫抽象被观察者(Observable)角色,一般用一个抽象类或者一个接口实现。
      (2)抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者角色一般用一个抽象类或者一个接口实现。
      (3)具体主题(ConcreteSubject)角色:将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者角色(Concrete Observer)。具体主题角色通常用一个具体子类实现。
      (4)具体观察者(ConcreteObserver)角色:存储于主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体观察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。 
       在类图中,从具体主题角色指向抽象观察者角色的合成关系,代表具体主题对象可以包含任意多个对抽象观察者对象的引用。由于java的抽象类是不可能有实例的,因此这些引用的的真实类型必定是ConcreteObserver类型,而这些引用的静态类型是Observer类型,这意味着主题对象不需要知道引用了哪些ConcreteObserver类型,而只知道抽象Observer类型,这就使得具体主题对象可以动态的维护一系列的对观察者对象的引用,并且在需要的时候调用每一个观察者的公有的update()方法。
       下面给出示意性代码:
 1.ject.java

package com.pattem.behavioral.Observer;

/**
 * 抽象主题角色
 * */
public interface Subject {
	
	//登记一个新的观察者对象
	public void attach(Observer observer);
	
	//删除一个已经登记过的观察者对象
	public void detach(Observer observer);
	
	//通知所有登记过的观察者对象
	public void notifyObserver();

}

2.ConcreteSubject.java

package com.pattem.behavioral.Observer;

import java.util.Enumeration;
import java.util.Vector;

import javax.sound.sampled.EnumControl;

public class ConcreteSubject implements Subject{

	private Vector<Observer> observersVector = new Vector<Observer>();
	
	public void attach(Observer observer) {
		observersVector.addElement(observer);
	}

	public void detach(Observer observer) {
		observersVector.removeElement(observer);
	}
	
	public void notifyObserver() {
		Enumeration enumeration = observers();
		while(enumeration.hasMoreElements()){
			((Observer)enumeration.nextElement()).update();
		}
	}
	
	public Enumeration observers(){
		return ((Vector)observersVector.clone()).elements();
	}

}

3.Observer.java

package com.pattem.behavioral.Observer;

/**
 * 抽象观察者角色
 * */
public interface Observer {
	
	//调用这个方法更新自己
	void update();

}

4.ConcreteObserver.java

package com.pattem.behavioral.Observer;

/**
 * 具体观察者角色
 * */
public class ConcreteObserver implements Observer{

	public void update() {
		
		//修改方法
		System.out.println("I am notified");
	}
}

         如果仔细考察主题功能的对象的功能时,可以发现它必须使用一个java集合来维护一个对所有的观察者对象的引用。而在前面所给出的实现里面,管理这个集合的方法是由抽象主题角色声明并由具体主题角色实现的。这才导致了类图中从具体主题角色到抽象观察者角色的连线。
       但是一个自然的问题就是,这些集合管理方法难道在每一个具体主题角色中都不同吗?答案是否定的。在大多数情况下,这些集合管理方法本身就是所有具体主题角色所共有的,因此这些方法连同集合本身都可以移动到抽象主题角色中去。同意由于notifyObserver()方法依赖集合对象,也可以移到抽象主题角色中去。  这就是第二种实现方案。其结构类图如下:   
                           
       下面给出抽象主题的源码:
Subject.java

package com.pattem.behavioral.Observer2;

import java.util.Enumeration;
import java.util.Vector;


/**
 * 抽象主题角色
 * */
public abstract class Subject {
	
	//保存对观察者对象的引用
	private Vector<Object> observerVector = new Vector<Object>();
	
	//登记一个新的观察者对象
	public void attach(Observer observer){
		observerVector.addElement(observer);
		System.out.println("Attach an observer");
	}

	//删除一个已经登记过的观察者对象
	public void detach(Observer observer){
		observerVector.removeElement(observer);
	}
	
	public void notifyObserver(){
		Enumeration<Object> enumeration = observers();
		while(enumeration.hasMoreElements()){
			((Observer)enumeration.nextElement()).update();
		}
	}
	//给出观察者聚集的 Enumeration对象
	public Enumeration<Object> observers(){
		return ((Vector)observerVector.clone()).elements();
	}
}

ConcreteSubject.java

package com.pattem.behavioral.Observer2;


/**
 * 具体主题角色
 * */
public class ConcreteSubject extends Subject {

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

Client.java

package com.pattem.behavioral.Observer2;

/**
 * 客户端代码 Client
 * */
public class Client {
	
	private static ConcreteSubject subject;
	private static Observer observer;
	
	public static void main(String[] args) {
		
		//创建主题对象
		subject = new ConcreteSubject();
		//创建观察者对象
		observer = new ConcreteObserver();
		//将观察者对象登记到
		subject.attach(observer);
		//改变主题对象的状态
		subject.change("new state");
	}
}

     在运行时,这个客户端首先创建了具体主题类的实例,以及一个观察对象,然后它调用主题对象的attach()方法,将这个观察者对象向主题对象登记,也就是将它加入到主题对象的集合中去。



java语言提供对观察者模式的支持

     
在java语言的java.util库里面,提供了一个Observable的类和一个Observer的接口,构成java语言对观察者模式的支持。(详情,请参考java.util.Observable 类源码)

© 著作权归作者所有

共有 人打赏支持
叶知秋
粉丝 25
博文 85
码字总数 103570
作品 0
浦东
程序员
私信 提问
设计模式--观察者模式

观察者模式(observer): 示例: 观察者模式测试类ObserverTest.java 主题接口类Subject.java 观察者接口类Observer.java 猎头类HeadHunterImpl.java 求职者类JobSeekerImpl.java...

有钱有爱
2016/04/09
7
0
iOS-观察者模式

前言 与其说发布订阅是观察者模式的别名,还不如说发布订阅本质上是一种特殊的观察者模式;两种模式都主要是用于解除一个对象与多个对象之间的耦合,即不管有多少个监听者(observer),都不...

麦兜卖鱼丸
2016/08/15
45
0
设计模式17——Observer设计模式

Observer观察者设计模式用于将对象的变化通知给感兴趣的用户。在Observer模式中的角色为主题(subject)与观察者(observer),观察者订阅它感兴趣的主题,一个主题可以被多个观 察者订阅,当...

小米米儿小
2014/01/26
0
0
PHP设计模式-观察者

PHP设计模式-观察者 一个对象状态发生改变后,会影响到其他几个对象的改变,这时候可以用观察者模式。一个对象通过添加一个attach方法允许观察者注册自己,使本身变得可观察。当被观察的对象...

侯施群
2016/07/13
0
0
zookeeper 观察者-学习笔记

除了leader和follow模式之外,还有第三种模式:observer模式。 observer和follower在一些方面是一样的。详细点来讲,他们都向leader提交proposal。 但与follower不同,observer不参与投票的过...

1066897515
06/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

EOS docker开发环境

使用eos docker镜像是部署本地EOS开发环境的最轻松愉快的方法。使用官方提供的eos docker镜像,你可以快速建立一个eos开发环境,可以迅速启动开发节点和钱包服务器、创建账户、编写智能合约....

汇智网教程
今天
14
0
《唐史原来超有趣》的读后感优秀范文3700字

《唐史原来超有趣》的读后感优秀范文3700字: 作者:花若离。我今天分享的内容《唐史原来超有趣》这本书的读后感,我将这本书看了一遍之后就束之高阁了,不过里面的内容一直在在脑海中回放,...

原创小博客
今天
19
0
IC-CAD Methodology知识图谱

CAD (Computer Aided Design),计算机辅助设计,指利用计算机及其图形设备帮助设计人员进行设计工作,这个定义同样可以用来近似描述IC公司CAD工程师这个岗位的工作。 早期IC公司的CAD岗位最初...

李艳青1987
今天
19
0
CompletableFuture get方法一直阻塞或抛出TimeoutException

问题描述 最近刚刚上线的服务突然抛出大量的TimeoutException,查询后发现是使用了CompletableFuture,并且在执行future.get(5, TimeUnit.SECONDS);时抛出了TimeoutException异常,导致接口响...

xiaolyuh
今天
10
0
dubbo 搭建与使用

官网:http://dubbo.apache.org/en-us/ 一,安装监控中心(可以不安装) admin管理控制台,monitor监控中心 下载 bubbo ops 这个是新版的,需要node.js环境,我没有就用老版的了...

小兵胖胖
今天
21
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部