观察者模式的定义:对象间定义一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。属于行为型模式。
观察者模式的核心在于观察者和被观察者解耦,通过类似于消息发送或广播的机制联动,使被观察者的变动能够被观察者知道并相应。
观察者模式的结构:观察者模式主要包括以下4个角色。
- 抽象主题(Subject):也叫抽象目标类,是指被观察的对象,它提供了增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
- 具体主题(Concrete Subject):也叫具体目标类,它实现了抽象主体中的方法,当具体主题的内部状态发生改变时,会通知所有已注册的观察者。
- 抽象观察者(Observer):它是一个抽象类或接口,它定义了响应被观察者通知的更新方法。
- 具体观察者(Concrete Observer):抽象观察者的具体实现,在得到被观察者的更改通知时更新自身的状态。
观察者模式的通用实现:
//抽象观察者
public interface Observer {
void update();
}
//具体观察者A
public class ConcreteObserverA implements Observer{
@Override
public void update() {
System.out.println("具体观察者A更新自身状态!");
}
}
//具体观察者B
public class ConcreteObserverB implements Observer{
@Override
public void update() {
System.out.println("具体观察者B更新自身状态!");
}
}
//抽象主题
public abstract class Subject {
protected List<Observer> observers = new ArrayList<Observer>();
//增加观察者方法
public void add(Observer observer) {
observers.add(observer);
}
//删除观察者方法
public void remove(Observer observer) {
observers.remove(observer);
}
//通知观察者方法
abstract void notifyObserver();
}
//具体主题
public class ConcreteSubject extends Subject{
@Override
void notifyObserver() {
System.out.println("被观察者发生改变...");
for (Observer obs : observers) {
obs.update();
}
}
}
//测试类
public class Test {
public static void main(String[] args) {
Subject subject = new ConcreteSubject();
Observer obsA = new ConcreteObserverA();
Observer obsB = new ConcreteObserverB();
subject.add(obsA);
subject.add(obsB);
subject.notifyObserver();
}
}
观察者模式的结构图:
观察者模式的应用实例:过马路时要遵守交通,红灯停,绿灯行。我们使用观察者模式来模拟过马路时交通信号灯的变化和路人的反应。
//抽象观察者
public interface IPerson{
//通过
void across(Color color);
}
//具体观察者
public class Zhangsan implements IPerson{
@Override
public void across(Color color) {
if(Color.green.equals(color)){
System.out.println("绿灯了,可以通过!!!");
}else {
System.out.println("红灯禁止通行!!!");
}
}
}
//具体观察者
public class Lisi implements IPerson{
@Override
public void across(Color color) {
if(Color.green.equals(color)){
System.out.println("绿灯了,可以通过!!!");
}else {
System.out.println("红灯禁止通行!!!");
}
}
}
//抽象主题
public abstract class AbstractTrafficSignal {
List<IPerson> personList = new ArrayList<>();
//增加观察者方法
public void add(IPerson person) {
personList.add(person);
}
//删除观察者方法
public void remove(IPerson person) {
personList.remove(person);
}
//信号灯改变
public abstract void change(Color color);
}
//具体主题
public class TrafficSignal extends AbstractTrafficSignal{
//信号灯改变
@Override
public void change(Color color) {
for (IPerson observer : personList) {
observer.across(color);
}
}
}
//测试类
public class Test {
public static void main(String[] args) {
AbstractTrafficSignal trafficSignal = new TrafficSignal();
IPerson zhangsan = new Zhangsan();
IPerson lisi = new Lisi();
trafficSignal.add(zhangsan);
trafficSignal.add(lisi);
trafficSignal.change(Color.RED);
trafficSignal.change(Color.GREEN);
}
}
在 Java 中,Jdk提供了 java.util.Observable 类和 java.util.Observer 接口,只要实现它们的子类就可以实现观察者模式。
1. Observable类:Observable 类是抽象目标类,它有一个 Vector 容器,用于保存所有要通知的观察者对象。
- void addObserver(Observer o) 方法:用于将新的观察者对象添加到 Vector 中。
- void deleteObserver(Observer o)方法:删除Vactor中的观察者。
- void notifyObservers(Object arg) 方法:调用Vactor中所有观察者对象的 update() 方法,通知它们数据发生改变。
- void setChange() 方法:设置一个 boolean 类型的内部标志位,注明目标对象发生了变化。当它为真时,notifyObservers() 才会通知观察者。
2. Observer 接口:Observer 接口是抽象观察者,它监视目标对象的变化,当目标对象发生变化时,观察者得到通知,并调用 void update(Observable o,Object arg) 方法,进行相应的工作。
//贴吧发言
public class Post extends Observable {
public void setNote(String note) {
System.out.println("贴吧发言:");
setChanged();
notifyObservers(note);
}
}
//观察者
public class Reader implements Observer{
private String name;
public Reader(String name){
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
String note = (String) arg;
System.out.println("===============================");
System.out.println(name+",您好,收到一条新的发言,内容:"+note);
}
}
//测试类
public class Test {
public static void main(String[] args) {
Post post = new Post();
Reader zhangsan = new Reader("zhangsan");
Reader lisi = new Reader("lisi");
post.addObserver(zhangsan);
post.addObserver(lisi);
post.setNote("大家好,我是新来的吧友小明。");
}
}
观察者模式的优点:
- 降低了观察者与被观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。
- 目标与观察者之间建立了一套触发机制。
- 实现了一对多通信机制。
观察者模式的缺点:
- 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
- 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。
- 事件通知呈线性关系,如果其中一个观察者更新事件异常,会影响后续的观察者接收通知。
观察者模式的应用场景:
- 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象。
- 当一个抽象模型有两个方面,其中一个方面依赖于另一方面时。
- 实现类似广播机制的功能,不需要知道具体收听者,只需分发广播,系统中感兴趣的对象会自动接收该广播。
- 多层级嵌套使用,形成一种链式触发机制,使得事件具备跨域(跨越两种观察者类型)通知。