观察者模式
来源:互联网 发布:北京大学软件共享平台 编辑:程序博客网 时间:2024/06/06 06:39
观察者模式
简介:
出版者+订阅者=观察者模式
Subject
主题接口,也即可观察者(Observable),对象使用此接口注册为观察者,或者把自己从观察着中删除。每个主题可以有多个观察者。
ConcreteSubject
一个具体主题实现了主题接口,除了注册和撤销之外,具体主题还实现了notifyObservers()方法,这个方法用来在主题状态改变时更行所有的观察者。具体主题也可能有设置和获取状态的方法。
Observer
所有潜在的观察者必须实现观察者接口,这个接口只有update()方法,当主题改变时,它被调用。
ConcreteObserver
具体的观察者可以是任何实现了Observer接口的类。观察者必须注册具体主题,一边接收更新。
基本原则:为了交互对象之间的松耦合设计而努力
观察者模式的定义:观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有的依赖者都会收到通知并自动更新。
观察者模式中,一对多的关系体现在哪里?
这个模式中,主题是具有状态的对象,并且可以控制这个状态,也就是说,是一个具有“状态”的主题。
另一方面,观察者使用这些状态,虽然这些状态并不属于他们。有多个观察者,依靠主题来告诉他们主题状态何时变了。
这就产生了一个关系,一个“主题”对多个“观察者”的关系
松耦合设计威力体现在哪里?
当两个对象松耦合,他们依然可以交互,但是不太清楚彼此的细节。观察者模式提供了一种对象设计,让主题和观察者松耦合。
类图:
实例:
主题1:游戏新闻对象:GameMsg
package com.mylearn.designmodel.observer;
import java.util.Observable;
/**
* Created by IntelliJ IDEA.
* User: yingkuohao
* Date: 13-10-31
* Time: 上午11:58
* CopyRight:360buy
* Descrption:
* To change this template use File | Settings | File Templates.
*/
public class GameMsg extends Observable {
private String msg;
private static String flag = "game";
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
sendMsg();
}
private void sendMsg() {
super.setChanged(); //开关
super.notifyObservers(); //通知消费者
}
}
主题2:头条新闻对象:HeadMsg
package com.mylearn.designmodel.observer;
import java.util.Observable;
/**
* Created by IntelliJ IDEA.
* User: yingkuohao
* Date: 13-10-31
* Time: 上午11:58
* CopyRight:360buy
* Descrption:
* To change this template use File | Settings | File Templates.
*/
public class HeadMsg extends Observable {
private String msg;
private static String flag = "head";
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
sendMsg();
}
private void sendMsg() {
super.setChanged();
super.notifyObservers(); //通知消费者,notify方法将遍历Observable中的Vector,找到其中的Observer,调用其update方法。
}
}
观察者A:只订阅游戏新闻
package com.mylearn.designmodel.observer;
import java.util.Observable;
import java.util.Observer;
/**
* Created by IntelliJ IDEA.
* User: yingkuohao
* Date: 13-10-31
* Time: 下午12:02
* CopyRight:360buy
* Descrption:
* To change this template use File | Settings | File Templates.
*/
public class ObserverA implements Observer {
private Observable observable;
public Observable getObservable() {
return observable;
}
public void setObservable(Observable observable) {
this.observable = observable;
observable.addObserver(this); //加入观察者 ,Observable类中维护了一个Vector,用于保存注册的观察者信息,
}
/**
* 相当于一个锚链接,当Observable中有新消息时,便会通知观察者,调用观察者的update方法。
*
* @param o
* @param arg
*/
public void update(Observable o, Object arg) {
if (o instanceof GameMsg) {
//主动拉消息
String msg = ((GameMsg) o).getMsg();
display(msg);
}
}
public void display(String msg) {
System.out.println("oye!get a game msg:" + msg);
}
}
观察者B:只订阅头条新闻
package com.mylearn.designmodel.observer;
import java.util.Observable;
import java.util.Observer;
/**
* Created by IntelliJ IDEA.
* User: yingkuohao
* Date: 13-10-31
* Time: 下午12:02
* CopyRight:360buy
* Descrption:
* To change this template use File | Settings | File Templates.
*/
public class ObserverB implements Observer {
private Observable observable;
public Observable getObservable() {
return observable;
}
public void setObservable(Observable observable) {
this.observable = observable;
observable.addObserver(this); //加入观察者
}
public void update(Observable o, Object arg) {
if (o instanceof HeadMsg) {
String msg = ((HeadMsg) o).getMsg();
display(msg);
}
}
public void display(String msg) {
System.out.println("oye!get a head msg:" + msg);
}
}
Test类:
package com.mylearn.designmodel.observer;
/**
* Created by IntelliJ IDEA.
* User: yingkuohao
* Date: 13-10-31
* Time: 下午12:06
* CopyRight:360buy
* Descrption:
* To change this template use File | Settings | File Templates.
*/
public class Test {
public static void main(String args[]) {
GameMsg gameMsg =new GameMsg();
HeadMsg headMsg =new HeadMsg();
ObserverA observerA =new ObserverA();
ObserverB observerB =new ObserverB();
observerA.setObservable(gameMsg);
observerB.setObservable(headMsg);
gameMsg.setMsg("dota 更新了!");
headMsg.setMsg("普京当选了!");
}
}
源码:
Observable类:抽象主题对象(即被观察者的父类)
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(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;
synchronized (this) {
/* We don't want the Observer doing callbacks into
* arbitrary code while holding its own Monitor.
* The code where we extract each Observable from
* the Vector and store the state of the Observer
* needs synchronization, but notifying observers
* does not (should not). The worst result of any
* potential race-condition here is that:
* 1) a newly-added Observer will miss a
* notification in progress
* 2) a recently unregistered Observer will be
* wrongly notified when it doesn't care
*/
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged(); // 当一个主题执行notify方法时,会把changed设为false,这样其他线程就会进不来,除非其他线程执行了setChange方法,所以,我们的实例中调用notify方法时都要先改变changed状态
}
//遍历观察者集合,分别执行callback方法,即update方法,这个是由我们的Observer接口约定的
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
//由此可以看到我们的notify方法跟Object的notify,wait一点关系都没有,只不过是方法的回调。
优点:
主题和观察者之间解耦,主题不用知道具体的观察者是谁,当新加观察者或删除观察者时,主题不用做任何改动,主题和观察者都是可插拔的。
缺点:
1. Observable是一个类而不是一个接口,无法实现多继承。
2. Observable把很多方法如setChanged方法保护起来,我们无法用聚合的方式把Observable聚合到自己定义的对象中来,违反了“多用组合,少用继承”的原则。
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- c primer plus 第二章习题摘录
- 如何提取ipa中的图片; iphone ios 如何制作越狱ipa安装文件
- Oracle中的NULL
- 用GDB调试程序
- 去掉字符串末尾的逗号
- 观察者模式
- Oracle 日期格式类型和日期函数 java操作数据库
- 不用安装oracle客户端访问数据库
- Android 恢复出厂设置的流程
- MFC窗口视频显示方法--OpenCV DirectShow模式
- 简单数组
- Performing Data Pump Exports and Imports
- TFS - 重建Analysis数据库或者修改Analysis数据库文件位置
- 用Maven构建Hadoop项目