1. 说明
当目标对象(被观察者)的状态发生变化时,自动通知观察它的对象。观察者模式常用于消息、事件驱动等。
实现步骤:
- 定义一个观察者接口,提供一个方法,用于被观察者状态发生变化时,观察者执行的动作。
- 所有的观察者需要实现观察者接口,用于接收状态变更的通知。
- 被观察者维护一个
List
,保存观察者们; - 被观察者提供注册(订阅)、删除(取消订阅)观察者的方法;
- 被观察者在自身状态发生变化(某些条件下)时,逐个通知已注册的观察者们(即逐个调用观察者的接口方法)。
2. 示例
观察者接口:
public interface Observer {
void update(SubJect subJect);
}
被观察者抽象对象:
public abstract class SubJect {
// 用来保存注册的观察者对象
private List<Observer> observers = new ArrayList<>();
// 观察者注册(订阅)
public void subscribe(Observer observer) {
observers.add(observer);
}
// 删除(取消订阅)
public void unsubscribe(Observer observer) {
observers.remove(observer);
}
/**
* 通知所有观察者
*/
protected void notifyObservers() {
for (Observer observer : observers) {
observer.update(this);
}
}
}
实际的观察者:
public class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(SubJect subJect) {
System.out.println("我是观察者:" + name + ",我观察到了对象状态变成了:" + ((ConcreteSubject)subJect).getSubjectState() );
}
}
实际的被观察者:
public class ConcreteSubject extends SubJect {
// 目标对象的状态
private String subjectState;
public String getSubjectState() {
return subjectState;
}
/**
* 状态变化时,通知观察者
*/
public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
this.notifyObservers();
}
}
测试类:
public class ObserverTest {
public static void main(String[] args) {
// 创建目标(主题)
ConcreteSubject subject = new ConcreteSubject();
// 创建观察者
ConcreteObserver concreteObserver = new ConcreteObserver("aaa");
ConcreteObserver concreteObserver2 = new ConcreteObserver("bbb");
ConcreteObserver concreteObserver3 = new ConcreteObserver("ccc");
// 注册观察者
subject.subscribe(concreteObserver);
subject.subscribe(concreteObserver2);
subject.subscribe(concreteObserver3);
// 目标发生变化
subject.setSubjectState("哈哈");
// 取消订阅
subject.unsubscribe(concreteObserver2);
// 目标再次变化时,已取消订阅的观察者不再接收消息
subject.setSubjectState("嘿嘿");
}
}
测试结果:
我是观察者:aaa,我观察到了对象状态变成了:哈哈
我是观察者:bbb,我观察到了对象状态变成了:哈哈
我是观察者:ccc,我观察到了对象状态变成了:哈哈
我是观察者:aaa,我观察到了对象状态变成了:嘿嘿
我是观察者:ccc,我观察到了对象状态变成了:嘿嘿
3. 总结
注意观察者接口的参数,并不是必须的,具体取决于应用场景,观察者接口方法最重要的作用是提供一个事件通知的入口,如在Netty
的ChannelInboundHandler
中,提供的channelRegistered
、channelRead
、channelReadComplete
等,其作用就类似于本文中的update
方法。