文档章节

观察者模式-常用设计模式

dapengking
 dapengking
发布于 2014/03/03 22:19
字数 1250
阅读 606
收藏 7

观察者模式

    今天记录下,常用设计模式的第二篇-观察者模式。说起来,我知道观察者模式这个名词,在目前我所知道的设计模式中算是比较早的。因为,在之前闲的时候,曾经自学过android开发,在ui设计中的按钮事件,我印象中就是基于观察者模式实现的。你可以创建一个监听器类的对象,实现当按钮被点击时需要进行的动作。然后将这个对象(其实也就所谓的观察者)注册给按钮。这样,当有鼠标点击按钮时,按钮就会通知所有注册了的监听器类对象,调用其中的事件处理方法。

用headfirst设计模式一书中所说的一句话来概括就是:“当有趣的事情发生时,可千万别错过了!”。

    没错,观察者模式可以帮助对象了解运行现况。不会错过该对象感兴趣的事。而且,对象还可以在运行时决定是否需要继续接受通知。

    再引用一个书中的比方。如果了解报纸的订阅是怎么一回事的话,就会好理解的多。因为它们之间根本就是一样的道理,只是名字不太一样罢了。报纸的出版者就是观察者模式中的“主题(Subject)”,而报纸的订阅者其实也就是我们所谓的“观察者”。

严格的定义:观察者模式定义了对象之间一对多的依赖关系,这样一来,当一个对象改变状态的时候,它的所有依赖对象都可以收到通知并且自动更新状态。

观察者模式的UML类图(图片转自百度图片)

稍微解释下上图的意思:


  1. 首先,遵循面向接口而非面向实现编程的原则,我们需要两个接口:主题(Subject)和观察者(Observer)。在主题接口中声明了一般主题类中最基础的三个方法接口,分别为注册观察者(registerObserver)、删除观察者(removeObserver)和通知观察者(notifyObserver)。而观察者接口中通常至少会声明update方法接口,update将来的实现,用来在观察者收到主题的通知后,作出具体的动作;
  2. 接着,应该实现ConcreteSubject类,并实现Subject接口中的方法。通常情况下,在ConcreteSubject类中会维护一个Observer的容器,用来盛放注册进来的观察者对象的引用;
  3. 最后,当ConcreteSubject类的对象感知到状态改变后,会调用notifyOBserver()方法,在notifyOBserver()的实现中,我们会遍历ConcreteSubject类中Observer的容器中的所有Observer引用,对于每一个引用的对象,调用其update()方法。

通过上面三步的介绍,应该能够比较清楚的理解了观察者模式的基本原理了。在我自己的理解看来,观察者模式,其实与我的上篇帖子中的策略模式的最基本的实现机制相似:也是采用组合的方式,某些对象(这里是观察者对象)的引用组合到某个类(这里指主题类对象)的对象中。当某个事件发生时,主题类对象会采用一定的算法(这个算法不确定,最简单的方式是采用数组作为容器,然后采用遍历数组的方式。)遍历所有的观察者对象引用,并逐一调用update()方法。

与策略模式设计的初衷虽然不同(1.策略模式是为了封装经常变化的逻辑,将经常变动的代码,从比较稳定的代码中剥离出来,从而实现代码复用,并且可以实现在程序运行时的动态组合,提高了程序的灵活性。2.而这里的观察者模式则是为了实现消息的灵活订阅,这种一对多的关系)。但是它们之间在实现上的区别很小,都是通过组合的方式实现的。

一段简单的代码:


package observer;

public interface Subject {

	public void registerObserver(Observer o);
	public void removeObserver(Observer o);
	public void notifyObserver();
	
}



package observer;

public interface Observer {
	public void update();
}



package observer;

import java.util.ArrayList;

public class ConcreteSubject implements Subject {

	private ArrayList<Observer> observers = new ArrayList<Observer>();
	
	@Override
	public void notifyObserver() {
		for (Observer observer : observers) {
			observer.update();
		}
	}

	@Override
	public void registerObserver(Observer o) {
		observers.add(o);
	}

	@Override
	public void removeObserver(Observer o) {
		observers.remove(o);
	}

}



package observer;

public class ConcreteObserver implements Observer {

	private String title = null;
	
	public ConcreteObserver(String title,Subject s) {
		this.title = title;
		s.registerObserver(this);
	}

	@Override
	public void update() {
		//观察者收到消息后的处理逻辑
		//
		//
		System.out.println(title + "收到了通知,并且相应了");
	}

}
//测试方法类
package observer;

public class Main {

	public static void main(String[] args) {
		Subject s = new ConcreteSubject();
		
		new ConcreteObserver("observer1",s);
		new ConcreteObserver("observer2",s);
		
		//模拟有事件发生时,调用notifyObserver()方法
		s.notifyObserver();
	}
}




运行结果:


--the end~




© 著作权归作者所有

共有 人打赏支持
dapengking
粉丝 7
博文 133
码字总数 53553
作品 0
东城
程序员
私信 提问
六个前端开发工程师必备的Web设计模式/模块资源

Yahoo的设计模式库 Yahoo的设计模式库包含了很多可以帮助开发设计人员解决遇到的问题的资源,包括开发中常常需要处理的导航,互动效果及其布局网格等大家常用的组件和模块 响应式设计模式库 ...

gbin1
2014/07/30
13
0
Ubuntu中vi卸载与安装/使用模式

Ubuntu中安装的vi是vim-common版本,与centos系统中vi使用方式不同,编辑使用不惯, 遂卸载重装,卸载命令:sudo apt-get remove vim-common 卸载完毕后重新安装;输入命令:sudo apt-get in...

唐十三郎
11/27
0
0
【设计模式笔记】(十六)- 代理模式

一、简述 代理模式(Proxy Pattern),为其他对象提供一个代理,并由代理对象控制原有对象的引用;也称为委托模式。 其实代理模式无论是在日常开发还是设计模式中,基本随处可见,中介者模式中...

MrTrying
06/24
0
0
设计模式已经陨落了?

你现在是坐在一个程序员旁边吗?如果是的话,那么在你读下面的段落之前,有一个简单的实验。让他们到一边去,问问他们两个问题并记录下答案。首先问他们“什么是设计模式?”然后再问“说出你...

oschina
2014/03/11
9.1K
69
《PHP设计模式大全》系列分享专栏

《PHP设计模式大全》已整理成PDF文档,点击可直接下载至本地查阅 https://www.webfalse.com/read/201739.html 文章 php设计模式介绍之编程惯用法第1/3页 php设计模式介绍之值对象模式第1/5页...

kaixin_code
11/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

springboot jpa 访问数据库

spring boot(五):spring data jpa的使用 SpringBoot非官方教程 | 第三篇:SpringBoot用JdbcTemplates访问Mysql

颖辉小居
18分钟前
3
0
Quartz + Oracle 分布式Job实现

简述 实现 依赖包 <dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.2.3</version><exclusions><exclusion><groupId>com.zax......

呼呼南风
24分钟前
5
0
崛起于Springboot2.X之集成规则引擎Drools(41)

1、创建Springboot项目,勾选Web模块和lombok插件 2、添加pom其他依赖 <dependency> <groupId>org.kie</groupId> <artifactId>kie-spring</artifactId> <version>7.11.0.Fin......

木九天
32分钟前
5
0
Kylin修改context-path方法

Kylin修改context-path比较麻烦,本身kylin是前后端分离的工程,修改不是只改war,还得改前端路径 步骤如下: 1、tomcat webapps 修改 kylin.war 修改成test.war 2、vi test.war 从index.htm...

litterMo
33分钟前
2
0
怎样使用Chrome浏览器截取整个网页?

1、打开控制台:Ctrl + Shift + I 2、命令执行:Ctrl + Shift + P 3、Capture full size screenshot 浏览器会自动下载截图图片,推荐过几个扩展功能: 1.全屏幕截取网页编辑共享神器-Awesom...

近在咫尺远在天涯
36分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部