1、观察者模式
观察者模式又被称为发布订阅模式。它定义了对象之间一对多的依赖,当一个对象状态发生改变时,它的所有依赖者都会收到通知并自动更新相关内容。
观察者模式主要有两个角色
- Subject 观察主题对象,也可以叫被观察或者被订阅对象。
- Observer 观察者或者订阅者对象,当
Subject
有变动,就会通知到每一个Observer。
我们按照定牛奶的方式来理解,Subject
实际上可以理解成奶厂,Observer
可以理解成为我们每个用户,而观察者模式就是在Subject
发生变化的时候,去通知每一个Observer
对象,以达到消息通知目的。
2、自己实现一个观察者模式
定义观察者主题对象
/**
* 观察者主题对象(被观察者)
*/
public interface Subject {
/**
* 订阅操作
*/
void attach(Observer observer);
/**
* 取消订阅操作
*/
void detach(Observer observer);
/**
* 通知变动
*/
void notifyChanged();
}
定义观察者观察人对象
/**
* 观察者订阅人对象
*/
public interface Observer {
/**
* 接收变动通知
*/
void update();
}
分别创建Subject和Observer对象的实现类
public class RealSubject implements Subject {
private List<Observer> observerList = new ArrayList<>();
@Override
public void attach(Observer observer) {
observerList.add(observer);
}
@Override
public void detach(Observer observer) {
observerList.remove(observer);
}
@Override
public void notifyChanged() {
for (Observer observer : observerList) {
observer.update();
}
}
}
public class RealObject1 implements Observer {
@Override
public void update() {
System.out.println("RealObject1 接收到了通知");
}
}
public class RealObject2 implements Observer {
@Override
public void update() {
System.out.println("RealObject2 接收到了通知");
}
}
Observer的实现可以是很多个,可以理解为平时一家奶厂,订奶用户肯定是有很多个。
调用实现
public class Test {
public static void main(String[] args) {
Subject subject = new RealSubject();
Observer observer = new RealObject();
subject.attach(observer);
subject.notifyChanged();
}
}
3、使用Java自带的观察者模式类实现
Java中提供了 java.util.Observable
和 java.util.
Observer 来实现观察者模式。
上面自己通过接口的方式,实现了一个观察者模式,但是Java自身也是有这方面的实现了,下面看看如何用Java自带的实现一个观察者模式
public class RealSubject extends Observable {
public void makeChanged() {
setChanged();
notifyObservers();
}
}
public class RealObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("调用了-->");
}
}
public class test {
public static void main(String[] args) {
RealSubject subject = new RealSubject();
RealObserver observer = new RealObserver();
subject.addObserver(observer);
subject.makeChanged();
}
}
调用的基本逻辑是一样的。Java已经帮我们把订阅和取消订阅操作都封装了起来,通知也进行了封装,并且进行了同步处理。只要需要注意的是,这里有个setChanged();,在发生变化之后,必须调用这个方法告诉发生了改变,否则不会正常处理消息的。
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;
synchronized (this) {
/* We don't want the Observer doing callbacks into
* arbitrary code while holding its own Monitor.
* The code where we extract each Observable from
* the Vector and store the state of the Observer
* needs synchronization, but notifying observers
* does not (should not). The worst result of any
* potential race-condition here is that:
* 1) a newly-added Observer will miss a
* notification in progress
* 2) a recently unregistered Observer will be
* wrongly notified when it doesn't care
*/
if (!changed) //这里的标志位就是setChanged处理的标志位
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
4、观察者模式的优缺点
优点
- 解耦,被观察者只知道观察者列表「抽象接口」,被观察者不知道具体的观察者。
- 被观察者发送通知,所有注册的观察者都会收到信息「可以实现广播机制」。
缺点
- 如果观察者非常多的话,那么所有的观察者收到被观察者发送的通知会耗时。
- 观察者知道被观察者发送通知了,但是观察者不知道所观察的对象具体是如何发生变化的。
- 如果被观察者有循环依赖的话,那么被观察者发送通知会使观察者循环调用,会导致系统崩溃。