文章目录
观察者模式
观察者模式中,有订阅者和发布者。发布者在发布消息后,所有订阅者都可以受到消息。
手动实现观察者模式
订阅者接口
observerCjw
package observer_cjw;
/**
*观察者接口
*/
public interface observerCjw {
/**
* 功能:把接收的消息打印出来.
*/
void say();
/**
* 功能:更新信息
*/
void setMsg(String msg);
}
订阅者实现类
observerCjwImpl
package observer_cjw;
public class observerCjwImpl implements observerCjw {
private String msg;
@Override
public void say() {
System.out.println("msg: " + msg);
}
@Override
public void setMsg(String msg) {
this.msg = msg;
}
}
发布者接口
observableCjw
package observer_cjw;
/**
*发布者接口
*功能:添加订阅者,删除订阅者,发布消息
*/
public interface observableCjw {
/**
* 功能:添加订阅者
*/
void addObserver(observerCjw observerCjw);
/**
* 功能:删除订阅者
*/
void delObserver(observerCjw observerCjw);
/**
* 功能:发布消息
*/
void upMsg(String msg);
}
发布者实现类
observableCjwImpl
package observer_cjw;
import java.util.List;
public class observableCjwImpl implements observableCjw {
private List<observerCjw> list;
public observableCjwImpl() {
super();
// TODO Auto-generated constructor stub
}
public observableCjwImpl(List<observerCjw> list) {
super();
this.list = list;
}
@Override
public void addObserver(observerCjw observerCjw) {
list.add(observerCjw);
}
@Override
public void delObserver(observerCjw observerCjw) {
list.remove(observerCjw);
}
@Override
public void upMsg(String msg) {
for (observerCjw observerCjw : list) {
observerCjw.setMsg(msg);
}
}
}
测试一下
package observer_cjw;
import java.util.ArrayList;
public class test01 {
public static void main(String[] args) {
// 创建3个订阅者
observerCjw observerCjw = new observerCjwImpl();
observerCjw observerCjw2 = new observerCjwImpl();
observerCjw observerCjw3 = new observerCjwImpl();
// 创建1个发布者
observableCjw observableCjw = new observableCjwImpl(new ArrayList<observerCjw>());
// 发布者添加订阅者
observableCjw.addObserver(observerCjw);
observableCjw.addObserver(observerCjw2);
observableCjw.addObserver(observerCjw3);
// 发布者发布消息
observableCjw.upMsg("早上好");
// 订阅者打印收到的消息
observerCjw.say();
observerCjw2.say();
observerCjw3.say();
System.out.println("-----------------------");
// 发布者发布消息
observableCjw.upMsg("中午好");
// 订阅者打印收到的消息
observerCjw.say();
observerCjw2.say();
observerCjw3.say();
System.out.println("-----------------------");
// 退订
observableCjw.delObserver(observerCjw2);
// 发布者发布消息
observableCjw.upMsg("晚上好");
// 订阅者打印收到的消息
observerCjw.say();
observerCjw2.say();
observerCjw3.say();
System.out.println("-----------------------");
}
}
打印输出
msg: 早上好
msg: 早上好
msg: 早上好
-----------------------
msg: 中午好
msg: 中午好
msg: 中午好
-----------------------
msg: 晚上好
msg: 中午好
msg: 晚上好
-----------------------
项目打包 提取码:2lod
环境:eclipse,jdk1.8
jdk实现观察者模式
jdk自带了实现观察者模式的接口和类。订阅者要实现 Observer
接口,发布者要继承 Observable
类。
这两个接口/类代码量不多,可以分析一下源码。
Observer接口
Observer
接口只有一个方法
public interface Observer {
void update(Observable o, Object arg);
}
方法 | 功能 |
---|---|
update | 更新消息 |
Observable类
字段名 | 类型 | 功能 |
---|---|---|
changed | boolean | |
obs | Vector | 存放订阅者 |
方法名 | 返回类型 | 功能 |
---|---|---|
Observable | void | 初始订阅者集合 |
addObserver | void | 添加订阅者 |
deleteObserver | void | 删除订阅者 |
notifyObservers | void | 发布消息 |
notifyObservers(有参) | void | 发布消息 |
deleteObservers | void | 删除所有的订阅者 |
setChanged | void | 标记需要更新 |
clearChanged | void | 标记不需要更新 |
hasChanged | boolean | 是否更新 |
countObservers | int | 返回订阅者数量 |
注释源码
package observer;
import java.util.Observer;
import java.util.Vector;
public class Observable {
// 标记是否需要更新,false表示更新完毕.
private boolean changed = false;
// 订阅者集合, 使用Vector集合来存放订阅者.
private Vector<Observer> obs;
// 初始化订阅者集合
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() {
notifyObservers(null);
}
/**
* 功能:发布消息
*/
public void notifyObservers(Object arg) {
// 存放订阅者
Object[] arrLocal;
// 把自己锁定
synchronized (this) {
// 判断是否更新完毕
if (!changed)
return;
// 把订阅者集合放入object数组中
arrLocal = obs.toArray();
// 标记更新完毕
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
// 把每一个订阅者都强转为Observer类型,每一个订阅者都执行update方法
((Observer)arrLocal[i]).update(this, arg);
}
/**
* 功能:删除所有订阅者
*/
public synchronized void deleteObservers() {
obs.removeAllElements();
}
/**
* 功能:设置需要更新
*/
protected synchronized void setChanged() {
changed = true;
}
/**
* 功能:标记不需要更新
*/
protected synchronized void clearChanged() {
changed = false;
}
/**
* 功能:返回是否需要更新标记
*/
public synchronized boolean hasChanged() {
return changed;
}
/**
* 功能:返回订阅者的数量
*/
public synchronized int countObservers() {
return obs.size();
}
}
为什么使用vector集合?
vector是线程安全的,大小自动变化的对象数组。
synchronized方法和synchronized代码块的使用?
增加/删除订阅者,返回订阅者数量,发布消息。使用synchronized方法/synchronized代码块做到了线程安全。
扩展性?
源码的设计非常好,订阅者的更新方法中可以使用发布者对象以及更新信息对象,相关联的信息,订阅者都可以获得。
必须实现Observable的子类?
是的,因为标记需要更新的方法是受保护的。不允许外界直接调用。必须实现其子类,将标记更新方法公开。
示例
订阅者
package observer;
import java.util.Observable;
import java.util.Observer;
/**
*订阅者
*/
public class ObserverCjw implements Observer{
/*
* 功能:将发布的消息打印出来
*/
@Override
public void update(Observable o, Object arg) {
System.out.println(this+":"+(String)arg);
}
}
发布者
package observer;
import java.util.Observable;
/**
*发布者
*/
public class ObservableCjw extends Observable{
/*
* 功能:公开setChanged方法
*/
public void setChanged() {
super.setChanged();
}
}
测试一下
package observer;
import java.util.Observer;
public class Test {
public static void main(String[] args) {
// 发布者
ObservableCjw observableCjw = new ObservableCjw();
// 订阅者
Observer oCjw = new ObserverCjw();
Observer oCjw2 = new ObserverCjw();
Observer oCjw3 = new ObserverCjw();
// 订阅
observableCjw.addObserver(oCjw);
observableCjw.addObserver(oCjw2);
observableCjw.addObserver(oCjw3);
// 发布消息
observableCjw.setChanged();
observableCjw.notifyObservers("早上好");
System.out.println("------------------");
// 发布消息
observableCjw.setChanged();
observableCjw.notifyObservers("中午好");
System.out.println("------------------");
// 退订
observableCjw.deleteObserver(oCjw2);
// 发布消息
observableCjw.setChanged();
observableCjw.notifyObservers("晚上好");
System.out.println("------------------");
}
}
输出打印
observer.ObserverCjw@6d06d69c:早上好
observer.ObserverCjw@7852e922:早上好
observer.ObserverCjw@4e25154f:早上好
------------------
observer.ObserverCjw@6d06d69c:中午好
observer.ObserverCjw@7852e922:中午好
observer.ObserverCjw@4e25154f:中午好
------------------
observer.ObserverCjw@6d06d69c:晚上好
observer.ObserverCjw@4e25154f:晚上好
------------------
项目打包 提取码:2zvh
环境:eclipse,jdk1.8