1. 概述
观察者模式是一种常见的设计模式,又叫发布-订阅(Publish/Subscribe)模式。本文主要介绍下观察者模式的基本概念,然后给出Java实现此设计模式的一个demo供大家参考。
2. 什么是观察者模式
将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象之间的一致性,而我们不希望为了维持一致性而使得各类紧密耦合,这样会给维护、扩展和重用都带来不便。
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
观察者设计模式的关键对象是主题Subject和观察者Observer,一个Subject可以有任意数目的一拉它的Observer,一旦Subject的状态发送了改变,所有的Observer都可以得到通知,Subject发出通知时并不需要知道谁是它的观察者,也就是说,具体观察者是谁,它根本不关心,也不需要知道。而任何一个具体观察者不知道也不需要知道其他观察者的存在。
3. 观察者模式类图
(1)Subject类
Subject类把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
(2)Observer类
Observer类即抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。
(3)ConcreteSubject类
ConcreteSubject类即具体主题,将有关状态存入具体观察者对象;在具体主题的内部状态发生改变时,给所有登记过的观察者发出通知。
(4)ConcreteObserver类
ConcreteObserver类即具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。
4. Java实现代码demo
(1)定义Subject类
package observer;
import java.util.ArrayList;
import java.util.List;
public abstract class Subject {
/** 观察者集合 */
private List<Observer> observers = new ArrayList<Observer>();
// 增加观察者
public void attach(Observer observer) {
observers.add(observer);
}
// 移除观察者
public void detach(Observer observer) {
observers.remove(observer);
}
// 通知观察者
public void notifyAllObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}
(2)定义Observer类
package observer;
public abstract class Observer {
public abstract void update();
}
(3)定义ConcreteSubject类
package observer;
public class ConcreteSubject extends Subject{
/**具体被观察者状态 */
private String subjectState;
public String getSubjectState() {
return subjectState;
}
public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
}
}
(4)定义ConcreteObserver类
package observer;
public class ConcreteObserver extends Observer {
/** 观察者名称 */
private String name;
/** 观察者状态 */
private String observerState;
/** 订阅主题 */
private ConcreteSubject subject;
public ConcreteObserver(Subject subject, String name) {
this.subject = (ConcreteSubject) subject;
this.name = name;
}
@Override
public void update() {
observerState = subject.getSubjectState();
System.out.println(String.format("观察者%s的最新状态是%s", name, observerState));
}
}
(5)客户端测试代码
package observer;
public class Test {
public static void main(String[] args) {
ConcreteSubject s = new ConcreteSubject();
s.attach(new ConcreteObserver(s,"X"));
s.attach(new ConcreteObserver(s,"Y"));
s.attach(new ConcreteObserver(s,"Z"));
s.setSubjectState("ABC");
s.notifyAllObservers();
}
}
测试结果
观察者X的最新状态是ABC
观察者Y的最新状态是ABC
观察者Z的最新状态是ABC