学习设计模式不光要学习设计模式的思想,还要去深入理解,为什么要用这个设计模式。
如何深入理解?读优秀的框架代码,看别人代码,了解它们的使用场景。 - - - 博主老师(感谢他)
本文先介绍了观察者模式的概念及简单实现。再贴了netty中对观察者的实现。最后再分享了netty这么设计的原因。
观察者模式 - 概念、简单实现及netty中的观察者
一、观察模式的概念及意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
二、观察者模式简单实现
实现:定义观察者和被观察者两种角色,被观察者持有一个观察者集合,当被观察者完成某个动作后,遍历观察者集合,调用update方法,逐个通知到注册在被观察者上的观察者。
Java的util包中定义了Observable类和Observer接口可以帮助我们实现观察者模式
定义一个被观察的对象(继承Observable类)
import java.util.Observable;
public class ObservableData extends Observable {
public void changeNum(int num) {
// Observable的方法
setChanged();
// Observable的方法
notifyObservers(num);
}
}
定义一个观察者(实现Observer接口)
public class DataObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
if (o instanceof ObservableData) {
System.out.println("观察到了:" + arg);
}
}
}
测试类
public class Test {
public static void main(String[] args) {
ObservableData observableData = new ObservableData();
DataObserver dataObserver = new DataObserver();
// 可以加好多观察者,观察者观察到数据变化后,可以做不同的事
observableData.addObserver(dataObserver);
observableData.changeNum(1);
}
}
输出:观察到了:1
可以看看Observer接口和Observable类的源码
package java.util;
public interface Observer {
void update(Observable o, Object arg);
}
package java.util;
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();
}
}
我们可以看到Obserable的实现非常简单,持有一个观察者集合,在notifyObservers的时候,遍历集合,调用update方法。另外,Obserable类在操作观察者集合的时候,都加了锁,保证了线程安全。
三、netty中的观察者模式
netty中的观察者:futrue的listener
Future最早源于jdk中的java.util.concurrent.Future
DefaultPromise 是netty中异步channel i/o操作的结果,提供了操作结果相关的一系列方法。继承Future,又对Futrue做了些扩展(Promise接口)。这个类非常重要,Futrue中的listener就是通过它实现的。
类结构:
源码:
public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
private Object listeners;
@Override
public Promise<V> addListener(GenericFutureListener<? extends Future<? super V>> listener) {
checkNotNull(listener, "listener");
synchronized (this) {
addListener0(listener);
}
if (isDone()) {
notifyListeners();
}
return this;
}
}
DefaultPromise就是我们的被观察者,持有了观察者的集合。观察者的集合就是这里的listeners, 还实现了addListener、removeListener等方法。
至于这里的listenners为什么是Object,我们可以看下addListener0方法
private void addListener0(GenericFutureListener<? extends Future<? super V>> listener) {
if (listeners == null) {
listeners = listener;
} else if (listeners instanceof DefaultFutureListeners) {
((DefaultFutureListeners) listeners).add(listener);
} else {
listeners = new DefaultFutureListeners((GenericFutureListener<?>) listeners, listener);
}
}
再看DefaultFutureListeners,其实持有了一个listener数组(其实我没搞懂他为什么要自己实现,直接用List不香吗?有大佬知道的,能否告知)
final class DefaultFutureListeners {
private GenericFutureListener<? extends Future<?>>[] listeners;
private int size;
private int progressiveSize;
public void add(GenericFutureListener<? extends Future<?>> l) {
GenericFutureListener<? extends Future<?>>[] listeners = this.listeners;
final int size = this.size;
if (size == listeners.length) {
this.listeners = listeners = Arrays.copyOf(listeners, size << 1);
}
listeners[size] = l;
this.size = size + 1;
if (l instanceof GenericProgressiveFutureListener) {
progressiveSize ++;
}
}
再回到DefaultPromise, 他在setSuccess成功之后,调用了notifyListeners();
public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
@Override
public Promise<V> setSuccess(V result) {
if (setSuccess0(result)) {
notifyListeners();
return this;
}
throw new IllegalStateException("complete already: " + this);
}
private void notifyListeners() {
EventExecutor executor = executor();
if (executor.inEventLoop()) {
final InternalThreadLocalMap threadLocals = InternalThreadLocalMap.get();
final int stackDepth = threadLocals.futureListenerStackDepth();
if (stackDepth < MAX_LISTENER_STACK_DEPTH) {
threadLocals.setFutureListenerStackDepth(stackDepth + 1);
try {
notifyListenersNow();
} finally {
threadLocals.setFutureListenerStackDepth(stackDepth);
}
return;
}
}
safeExecute(executor, new Runnable() {
@Override
public void run() {
notifyListenersNow();
}
});
}
}
暂时忽略netty里的线程模型,这里不管是不是当前线程发起的,notifyListenersNow();
继续看notifyListenersNow()
private void notifyListenersNow() {
Object listeners;
synchronized (this) {
// Only proceed if there are listeners to notify and we are not already notifying listeners.
if (notifyingListeners || this.listeners == null) {
return;
}
notifyingListeners = true;
listeners = this.listeners;
this.listeners = null;
}
for (;;) {
if (listeners instanceof DefaultFutureListeners) {
notifyListeners0((DefaultFutureListeners) listeners);
} else {
notifyListener0(this, (GenericFutureListener<?>) listeners);
}
synchronized (this) {
if (this.listeners == null) {
// Nothing can throw from within this method, so setting notifyingListeners back to false does not
// need to be in a finally block.
notifyingListeners = false;
return;
}
listeners = this.listeners;
this.listeners = null;
}
}
}
又调用了 notifyListener0, 在notifyListener0中,遍历了观察者列表,最终调用了operationComplete(future)方法。通知观察者,操作完成了。
private void notifyListeners0(DefaultFutureListeners listeners) {
GenericFutureListener<?>[] a = listeners.listeners();
int size = listeners.size();
for (int i = 0; i < size; i ++) {
notifyListener0(this, a[i]);
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private static void notifyListener0(Future future, GenericFutureListener l) {
try {
l.operationComplete(future);
} catch (Throwable t) {
logger.warn("An exception was thrown by " + l.getClass().getName() + ".operationComplete()", t);
}
}
观察者接口
public interface GenericFutureListener<F extends Future<?>> extends EventListener {
void operationComplete(F future) throws Exception;
}
netty中可以通过监听器的方式获取I/O操作结果,可以同时添加一个或多个。在I/O操作完成,会回调operationComplete方法,并把future作为入参传进去。
就此,我们了解了观察者模式,也看到了netty中观察者模式的实现。
netty观察者的思考
对于netty中的这个场景,观察者模式被用在了I/O结果监听上。首先netty是基于NIO,它的结构是异步的,I/O操作的完成时间无法预测。Future的get会直接阻塞,而超时时间又不能精准的设置。异步通知回调operationComplete是非常棒的解决方案。
其实Android中,对一个按钮绑定监听时间,也是观察者的思想
OnClickListener是观察者,mBtn是被观察者。
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
当对象发生改变,要通知其他对象的时候,就可以使用观察者。
[1] https://www.runoob.com/design-pattern/observer-pattern.html
[2] 李林锋·netty权威指南 中国工信出版社