设计模式:观察者模式

[b]观察者模式是一种常用的依赖之间松耦合的设计模式,又叫发布-订阅(Publish/Subscribe)模式或监听模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象——被监听者——在状态上发生变化时,会通知所有观察者对象(监听者),使它们能够自动更新自己。[/b]
在平常的生活中,很多人都喜欢听单田芳老爷子讲的评书,通常是在每天12:30开讲,这时候喜欢评书的听众会把收音机调到某个有单老爷子评书的频道,就可以收听自己喜欢的评书了。造这个示例中,有单老爷子评书的频道就是一个主题,而听众就是观察者,而观察者将收音机频道调到评书的的频道的动作就是注册事件。
在观察者模式中,又分为推模型和拉模型两种方式。
   ●推模型
     主题对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。
   ●拉模型
     主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象
观察者模式的优点:
●支持松耦合和减少依赖性。客户端不再依赖于观察器,因为通过使用主体和 Observer 接口对客户端进行了隔离。许多框架具有此优点,在这些框架中的应用程序组件可以注册为当(低级)框架事件发生时得到通知。结果,框架将调用应用程序组件,但不会依赖于它。
●观察器数目可变。观察器可以在运行时附加和分离,因为主体对于观察器数目没有任何假定。此功能在这样的情况下是很有用的:观察器数在设计时是未知的。例如,如果用户在应用程序中打开的每个窗口都需要一个观察器。
我们本节主要讲基于“推模型”的观察者模式。
下面我们来看一下观察者模式的类图:
[img]http://dl2.iteye.com/upload/attachment/0084/8476/35234046-7bd6-3084-bce3-89cc0c53db3d.gif[/img]
[b]Subject角色:[/b]可以是一个接口或抽象类,主题角色把所有的观察者对象的引用保存在一个列表里;每个主题都可以有任何数量的观察者。主题提供一个接口可以加上或撤销观察者对象;主题角色又叫做抽象被观察者(Observable)角色;
[b]Observer角色:[/b]为所有的具体观察者定义一个接口,在得到通知时更新自己;
[b]ConcreteSubject角色:[/b]具体主题,保存对具体观察者对象有用的内部状态;在这种内部状态改变时给其观察者发出一个通知;具体主题角色又叫作具体被观察者角色;
[b]ConcreteObserver角色:[/b]具体观察者,保存一个指向具体主题对象的引用;和一个与主题的状态相符的状态。具体观察者角色实现抽象观察者角色所要求的更新自己的接口,以便使本身的状态与主题的状态自恰。
下面我们再来看一下具体的代码:

package org.pattern.observer;

/**
* 主题接口
* @author JackyChen
*
*/
public interface ISubject {

/**
* 注册观察者
* @param observer 观察者
*/
void attach(IObserver observer);

/**
* 删除观察者
* @param observer 观察者
*/
void detach(IObserver observer);

/**
* 给所有观察者发信息
*/
void notifyObservers();

}


package org.pattern.observer;

/**
* 观察者接口
* @author JackyChen
*
*/
public interface IObserver {

void update(String msg);

}


package org.pattern.observer;

/**
* 具体观察者
* @author JackyChen
*
*/
public class ConcreteObserver implements IObserver {

/**
* @param msg 从主题接收到的信息
*/
public void update(String msg) {
System.out.println("Observer(" + this.hashCode() + ") 接收到了:" + msg);
//具体逻辑由用户决定...
}

}


package org.pattern.observer;

import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* 具体主题
* @author JackyChen
*
*/
public class ConcreteSubject implements ISubject {

private Vector<IObserver> observersVector = new Vector<IObserver>();
/**
* Executors.newFixedThreadPool线程池线程数,由服务器可用的CPU核心数量决定
*/
private static final int numThread = Runtime.getRuntime().availableProcessors()
;

@Override
public void attach(IObserver observer) {
observersVector.add(observer);
}

@Override
public void detach(IObserver observer) {
observersVector.remove(observer);
}

@Override
public void notifyObservers() {
//这个方法会有一些问题,由于是在ConcreteSubject线程内遍历观察者列表,
//故如果某一个观察者爆了异常的话,其他的观察者就不会被调用,可以改为
//由多线程来对每一个观察者的调用
/**
* for(IObserver observer : observersVector){
* observer.update(this.hashCode() + " 状态变了。");
* }
*/
ExecutorService exec = Executors.newFixedThreadPool(numThread);
for(final IObserver observer : observersVector){
exec.execute(new Runnable(){
@Override
public void run() {
observer.update("状态变了。");
}

});
}
exec.shutdown();
}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值