文档章节

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

dapengking
 dapengking
发布于 2014/03/03 22:19
字数 1250
阅读 604
收藏 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
东城
程序员
私信 提问
JavaScript设计模式之观察者模式

前言 准备研究一下MVVM的一些东西,由于MVVM运用了观察者模式的思想,因此翻开了《JavaScript设计模式与开发实践》一书,将观察者模式学习了一遍,顺便有对一些常用的设计模式进行一些了解,...

Srtian
05/22
0
0
编程中的那些经典套路——设计模式汇总

在正式阅读前,我先谈谈我们该用什么姿势和心态学习设计模式: 如果你还没有过多的编程经验(泛指半年以下),我建议你把它当做小说来看,能看懂多少是多少,因为半年以下经验的程序员用到设...

gzchen
08/27
0
0
编程中的那些套路——关于策略模式

该文章属于《编程中的那些经典套路——设计模式汇总》系列,并且以下内容基于语言PHP 今天讲讲策略模式,策略模式 和工厂模式十分相像(或者说在代码逻辑层面,他们是一样的)。 但策略模式与...

gzchen
08/27
0
0
Java设计模式 create FactoryMethod

工厂模式是我们最常用的模式了,著名的Jive论坛,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。 为什么工厂模式是如此常用?因为工厂模式就相当于创建实例对象的new,我们经...

神勇小白鼠
2011/05/18
0
0
JavaScript常用设计模式

设计模式 设计模式是一种在长时间的经验与错误中总结出来可服用的解决方案。 设计模式主要分为3类: 创建型设计模式:专注于处理对象的创建 Constructor构造器模式,Factory工厂模式,Singl...

a独家记忆
07/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

延迟队列实现精准的订单超时取消--自我记录备份

订单的超时取消很多系统采用定时任务,实际上达不到要求。我用的是延迟队列,但缺点是只实现了基于jvm的,分布式采用的是修改之前去查询订单状态,以及分布式锁获取的方式来控制,这样获得锁...

checkboxMan
30分钟前
1
0
storm 环境搭建

1.下载解压 下载地址:http://storm.apache.org/downloads.html #下载wget https://www-us.apache.org/dist/storm/apache-storm-1.2.2/apache-storm-1.2.2.tar.gz#解压tar -zxf apache......

MrPei
44分钟前
1
0
Python Base - 读写文件,字符串拼接,单引号

字符转义 读写文件cvs 字符串拼接,替换 import csvcsv_file_name = 'cardbin.csv'# insert into `card_bin_code` (name_of, code_of, card_no_prefix, bank_code) values ('中国银行......

园领T
46分钟前
1
0
基于JQUERY BOOTSTRAP 最简单的loading遮罩层

<%--loading遮罩层--%><div class="modal fade" id="loadingModal" backdrop="static" keyboard="false">   <div style="width: 200px;height:20px; z-index: 20000; position: abs......

颖辉小居
46分钟前
1
0
springboot+kafka

1,首先springboot对kafka的支持也很好,同样是在配置文件中配置好参数,然后就可以直接使用。先说一下,很简单,,,不要怕 2,我用的依赖是 <dependency> <groupId>org.springframewor...

我真是小菜鸡
50分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部