概述
观察者模式(0bserver Pattern),又叫发布-订阅
(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。定义一种一对多的依赖关系,一个主题对象可被多个观察者对象同时监听,使得每当主题对象状态变化时,所有依赖于它的对象都会得到通知并被自动更新。
属于行为型模式。
生活场景
APP角标通知
起床闹钟设置
使用场景
1、当一个抽象模型包含两个方面内容,其中一个方面依赖于另一个方面;
2、其他一个或多个对象的变化依赖于另一个对象的变化;
3、实现类似广播机制的功能,无需知道具体收听者,只需忿发方播,系统中感兴趣的对象会自动接收该广播;
4、多层级嵌套使用,形成一种链式触发机制,、使得事件具备跨域(跨越两种观察者类型)通知。
优点
1、观察者和被观察者是松耦合(抽象耦合)的,符合依赖倒置原则;
2、分离了表示层(观察者)和数据逻辑层(被观察者),并且建立了一套触发机制,使得数据的变化可以响应到多个表示层上;
3、实现了一对多的通讯机制,支持事件注册机制,支持兴趣分发机制,当被观察者触发事件时,只有感兴趣的观察者可以接收到通知。
缺点
1、如果观察者数量过多,则事件通知会耗时较长;
2、事件通知呈线性关系,如果其中一个观察者处理事件卡壳,会影响后续的观察者接收该事件;
3、如果观察者和被观察者之间存在循环依赖,则可能造成两者之间的循环调用,导致系统崩溃;
代码栗子#老师关心学生#jdk实现
// 被观察者继承Observable
public class Student extends Observable {
private String name = "童鞋";
private static final Student student = new Student();
private Student() {
}
public static Student getInstance() {
return student;
}
public String getName() {
return name;
}
/**
* 女神发小脾气,然后小强,大强去观察
*
* @param question
*/
public void publishQuestion(Question question) {
System.out.println(question.getUserName() + this.name + question.getContent());
setChanged();
notifyObservers(question);
}
}
// 老师是观察者
public class Teacher implements Observer {
private String name;
public Teacher(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
Student gper = (Student) o;
Question question = (Question) arg;
System.out.println("==================");
System.out.println(name + ",你好! \n" +
"您收到了一个来自" + gper.getName() + "的感冒信息,希望您处理。症状内容如下:\n" + question.getContent() +
"\n" + "感冒人:" + question.getUserName());
}
}
// 俺是被关系的东西
public class Question {
private String userName;
private String content;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
jdk实现
public class Observable {
// 是否以改变
private boolean changed = false;
// 观察者
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;
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();
}
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();
}
}
// 观察者实现这个行为
public interface Observer {
//
void update(Observable o, Object arg);
}
总结:jdk代理,一个类,一个接口,一个类是被观察者类,一个接口是观察者接口,
学生继承Observable,添加老师(实现行为观察者的Observer),
然后调用方法 setChanged();notifyObservers(question);就可以提醒所有的观察者了;
图1-1:
代码栗子#发布事件#guava
// 观察者
public class GuavaEvent {
@Subscribe
public void observer(String str) {
System.out.println("执行observer方法,传参为:" + str);
}
}
public static void main(String[] args) {
EventBus eventBus = new EventBus();
GuavaEvent guavaEvent = new GuavaEvent();
eventBus.register(guavaEvent);
eventBus.post("xq");
}
// 执行observer方法,传参为:xq
guava观察者代码解析
public class EventBus {
public void register(Object object) {
this.subscribers.register(object);
}
private final SubscriberRegistry subscribers;
private static final Logger logger = Logger.getLogger(EventBus.class.getName());
private final String identifier;
private final Executor executor;
private final SubscriberExceptionHandler exceptionHandler;
private final SubscriberRegistry subscribers;
private final Dispatcher dispatcher;
EventBus(String identifier, Executor executor, Dispatcher dispatcher, SubscriberExceptionHandler exceptionHandler) {
this.subscribers = new SubscriberRegistry(this);
this.identifier = (String)Preconditions.checkNotNull(identifier);
this.executor = (Executor)Preconditions.checkNotNull(executor);
this.dispatcher = (Dispatcher)Preconditions.checkNotNull(dispatcher);
this.exceptionHandler = (SubscriberExceptionHandler)Preconditions.checkNotNull(exceptionHandler);
}
}
// 以后补吧
1