1 简介
在实际生活中我们应该都有碰过过这个场景,那就是主题和订阅,一旦你订阅了主题,一有什么消息活动都会发送给你,
一个主题一般会有一个或多个订阅,这就是观察者模式了
2 实例
其实jdk 的java.utils 包里就已经帮我们写好了被观察者的主要功能,我们只需要扩展就行了,源码我已经翻译了
3 UML
代码:
package com.sl.demo.Observable;
import java.util.Vector;
/**
* 被观察者(主题)
* @author pengkun
*
*/
public class Observable {
//标识(是否有发生改变)
private boolean changed = false;
//自动增长的对象数组
private Vector<Observer> obs;
/**
* 构造行数初始化一个0个观察者自动增长的对象数组
*/
public Observable() {
obs = new Vector<>();
}
/**
* 添加一个观察者(如果传入null就直接跑出NullPointerException异常)
* @param o
*
*/
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
/**
* 删除一个观察者
* @param o
*/
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
/**
* 无参
* 如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。
*/
public void notifyObservers() {
notifyObservers(null);
}
/**
* 有参
* 如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。
*/
public void notifyObservers(Object arg) {
Object[] arrLocal;
//双重锁(防止线程不安全)
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
//通知每个观察者
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
/**
* 删除一个观察者
*/
public synchronized void deleteObservers() {
obs.removeAllElements();
}
/**
*
* 标记此 Observable 对象为已改变
*/
protected synchronized void setChanged() {
changed = true;
}
/**
* 指示对象不再改变,或者它已对其所有的观察者通知了最近的改变
*/
protected synchronized void clearChanged() {
changed = false;
}
/**
* 判断对象是否改变
* @return
*/
public synchronized boolean hasChanged() {
return changed;
}
/**
* 返回观察者的个数
* @return
*/
public synchronized int countObservers() {
return obs.size();
}
}
package com.sl.demo.Observable;
/**
* 被观察者(旭旭宝宝直播间)
* @author pengkun
*
*/
public class Subject extends Observable {
/**
* 业务方法
*/
public void sendMassage(String massage) {
if(true) {
//标记此 Observable 对象为已改变的对象
super.setChanged();
}
notifyObservers(massage);
}
}
观察者接口
package com.sl.demo.Observable;
/**
* 观察者接口
* @author pengkun
*
*/
public interface Observer {
//只要被观察者(主题)对象改变了就调用此方法
void update(Observable o, Object arg);
}
package com.sl.demo.Observable;
/**
* 观察者
* @author pengkun
*
*/
public class JMSOvserver implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("收到一条消息:"+arg);
}
}
测试:
@Test
public void test() {
//被观察这(主题:旭旭宝宝直播间)
Subject subject=new Subject();
//观察者(订阅人:观众)
Observer observer1=new JMSOvserver();
Observer observer2=new JMSOvserver();
Observer observer3=new JMSOvserver();
//订阅他装逼王直播间,好一有装B视频就能知道
//现在有三个死肥仔订阅了他的直播间
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.addObserver(observer3);
//现在老吊要直播了
subject.sendMassage("增幅亡,强化亡,黑铁太上皇开始直播啦!感紧来围观");
System.out.println("-------------------------------");
//现在有个死肥仔取消订阅了
subject.deleteObserver(observer3);
subject.sendMassage("增幅亡,强化亡,黑铁太上皇开始直播啦!感紧来围观");
}
结果:
收到一条消息:增幅亡,强化亡,黑铁太上皇开始直播啦!感紧来围观
收到一条消息:增幅亡,强化亡,黑铁太上皇开始直播啦!感紧来围观
收到一条消息:增幅亡,强化亡,黑铁太上皇开始直播啦!感紧来围观
-------------------------------
收到一条消息:增幅亡,强化亡,黑铁太上皇开始直播啦!感紧来围观
收到一条消息:增幅亡,强化亡,黑铁太上皇开始直播啦!感紧来围观
总结:
1)主题要知道哪些观察者对其进行监测,说明主题类中一定有一个集合类成员变量,添加和删除及判断这些观察者对象是否存在。
2)观察者类一定是多态的,有共同的父类接口。
3)主题完成的功能基本是固定的,添加观察者、撤销观察者、通知消息给观察者及引起观察者响应(即“拉”数据),可以抽象出来