设计模式:观察者模式 - 概念、简单实现及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权威指南 中国工信出版社

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值