定义:在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。
类图:
代码:
定义可观察者(发布者)接口
/**
* 报社接口
* @author z_hh
* @time 2018年7月23日
*/
public interface NewspaperOffice {
/**
* 用户注册
* @param o 读者
*/
void registerReader(Reader o);
/**
* 用户取消订阅
* @param o 读者
*/
void removeReader(Reader o);
/**
* 通知所有读者
*/
void notifyReaders();
}
定义可观察者(发布者)实现类
/**
* 新华报社
* @author z_hh
* @time 2018年7月23日
*/
public class PeopleNewspaper implements NewspaperOffice {
// 所有已订阅读者的集合
private List<Reader> observers;
// 报纸最新期数
private int latestTerm;
// 构造器
public PeopleNewspaper() {
observers = new ArrayList<>();
}
/**
* 新用户注册
* @param o 读者
*/
@Override
public void registerReader(Reader o) {
if (Objects.nonNull(o)) {
System.out.println("新用户注册:" + o.getClass().getSimpleName());
observers.add(o);
}
}
/**
* 用户取消订阅
* @param o 读者
*/
@Override
public void removeReader(Reader o) {
if (Objects.nonNull(o)) {
System.out.println("用户取消订阅:" + o.getClass().getSimpleName());
observers.remove(o);
}
}
/**
* 提醒所有读者
*/
@Override
public void notifyReaders() {
if (observers.isEmpty()) {
System.out.println("没有订阅者!");
return;
}
observers.forEach(observer -> observer.update(latestTerm));
}
/**
* 发布新报纸
*/
public synchronized void publishNewspaper() {
latestTerm++;
notifyReaders();
}
/**
* 获取最新报纸期数
* @return
*/
public int getLatestTerm() {
return latestTerm;
}
}
定义观察者(订阅者)接口
/**
* 读者接口
* @author z_hh
* @time 2018年7月23日
*/
public interface Reader {
/**
* 定义更新接口,提供给报社调用
* @param latestTerm
*/
void update(int latestTerm);
}
定义观察者(订阅者)公共抽象类
/**
* 抽象读者,提取公共部分
* @author z_hh
* @time 2018年7月23日
*/
public abstract class AbstractReader implements Reader {
protected NewspaperOffice newspaperOffice;
/**
* 提供给子类默认构造器
* @param newspaperOffice
*/
public AbstractReader(NewspaperOffice newspaperOffice) {
this.newspaperOffice = newspaperOffice;
newspaperOffice.registerReader(this);
}
/**
* 注册
* @param newspaperOffice
*/
// 可以设置为钩子方法
public abstract void register(NewspaperOffice newspaperOffice);
/**
* 取消订阅
* @param newspaperOffice
*/
// 可以设置为钩子方法
public abstract void remove(NewspaperOffice newspaperOffice);
}
定义观察者(订阅者)实现类
/**
* 读者周先生
* @author z_hh
* @time 2018年7月23日
*/
public class ZhouSir extends AbstractReader {
public ZhouSir(NewspaperOffice newspaperOffice) {
super(newspaperOffice);
}
@Override
public void update(int latestTerm) {
System.out.println("我是周先生,收到了第" + latestTerm + "期的报纸");
}
@Override
public void register(NewspaperOffice newspaperOffice) {
newspaperOffice.registerReader(this);
}
@Override
public void remove(NewspaperOffice newspaperOffice) {
newspaperOffice.removeReader(this);
}
}
/**
* 李先生
* @author z_hh
* @time 2018年7月23日
*/
public class LiSir extends AbstractReader {
public LiSir(NewspaperOffice newspaperOffice) {
super(newspaperOffice);
}
@Override
public void update(int latestTerm) {
System.out.println("我是李先生,收到了第" + latestTerm + "期的报纸");
}
@Override
public void register(NewspaperOffice newspaperOffice) {
newspaperOffice.registerReader(this);
}
@Override
public void remove(NewspaperOffice newspaperOffice) {
newspaperOffice.removeReader(this);
}
}
测试:
public class Test {
public static void main(String[] args) {
// 创建新华报社,开始没有读者
PeopleNewspaper peopleNewspaper = new PeopleNewspaper();
peopleNewspaper.publishNewspaper();
System.out.println("--------------完美分割线--------------");
// 两位读者注册
AbstractReader zhou = new ZhouSir(peopleNewspaper);
AbstractReader li = new LiSir(peopleNewspaper);
peopleNewspaper.publishNewspaper();
// 周先生取消订阅
System.out.println("--------------完美分割线--------------");
zhou.remove(peopleNewspaper);
peopleNewspaper.publishNewspaper();
// 周先生重新订阅,李先生取消订阅
System.out.println("--------------完美分割线--------------");
zhou.register(peopleNewspaper);
li.remove(peopleNewspaper);
peopleNewspaper.publishNewspaper();
}
}
结果:
没有订阅者!
--------------完美分割线--------------
新用户注册:ZhouSir
新用户注册:LiSir
我是周先生,收到了第2期的报纸
我是李先生,收到了第2期的报纸
--------------完美分割线--------------
用户取消订阅:ZhouSir
我是李先生,收到了第3期的报纸
--------------完美分割线--------------
新用户注册:ZhouSir
用户取消订阅:LiSir
我是周先生,收到了第4期的报纸
注意:该案例的可观察者和观察者均为我们自己定义,这样有利于加深对观察者模式的理解。
JDK也提供了可观察者和观察者的接口,方便我们使用,后面我们将做讲解。