Filed under 模式

在观察者模式中使用弱引用

观察者模式一般都用inner class来实现,比如Android中如下的类:

public abstract class AbstractCursor {
    public void setNotificationUri(ContentResolver cr, Uri notifyUri) {
            mSelfObserver = new SelfContentObserver(this);
        }
    }

     /**
     * Cursors use this class to track changes others make to their URI.
     */
    protected static class SelfContentObserver extends ContentObserver {
        WeakReference mCursor;

        public SelfContentObserver(AbstractCursor cursor) {
            super(null);
            mCursor = new WeakReference(cursor);
        }

        @Override
        public boolean deliverSelfNotifications() {
            return false;
        }

        @Override
        public void onChange(boolean selfChange) {
            AbstractCursor cursor = mCursor.get();
            if (cursor != null) {
                cursor.onChange(false);
            }
        }
    }
}

这里使用了很少见的WeakReference(弱引用):

weak-ref

因为在一般的Observer模式中,对于observer本身可能因为忘记unregister(或者在异常情况下没有unregister),这会导致内存的泄漏。这里在AbstractCursor和observer之间建立了弱引用,让前者可以及时得到回收。而observer和event source还是强引用,可能因为observer还是很亲量级的原因吧。

比较如下的另外一种实现,这种实现更加普遍:

public abstract class CursorAdapter  {
    protected void init(Context context, Cursor c, boolean autoRequery) {
        mChangeObserver = new ChangeObserver();
    }
    private class ChangeObserver extends ContentObserver {
        public ChangeObserver() {
            super(new Handler());
        }

        @Override
        public boolean deliverSelfNotifications() {
            return true;
        }

        @Override
        public void onChange(boolean selfChange) {
            onContentChanged();
        }
    }

如果你对内部类很熟悉的话(我是一点都不熟,重翻了遍thinking in java,经典啊),就会发现最前面的那种实现其实是nested class,后面一种才是inner class,由于inner class默认存在一个到“父类”的强引用,所以如果要用弱引用的话,必须把它改造成nested class(static class必为nested class),通过构造函数来传递“父类”的引用。

另:我用Rational Team Concert的Find bugs,对没有使用内置强引用的inner class但是没有声明为static的,有这样的建议:

Pattern: Should be a static inner class
id: SIC_INNER_SHOULD_BE_STATIC, type: SIC, category: PERFORMANCE

This class is an inner class, but does not use its embedded reference to the object which created it.  This reference makes the instances of the class larger, and may keep the reference to the creator object alive longer than necessary.  If possible, the class should be made static.

弱引用孙卫琴老师的这篇对象的强、软、弱和虚引用讲的很透彻,虽然没有多高明多复杂的地方,但是简单明了,难得。

OSGi的白板模式(White board Pattern)

这个模式主要是来对付Listener Patter(或者Observer Pattern),具体来说,后者的缺点在:

  • 产生了很多的类,比如很多情况下,一个event source只对应一个listener,这种浪费在手机这种受限设备上是一个不得不考虑的问题。
  • event source和listener的管理复杂,比如注册和注销,因为这两者可能都很动态,不能保证自己需要对方时对方是工作的,或者说难以达到消息的可靠性。这两者之间的依赖太明显,太直接。

White Board引入了event broker,作为两者间的桥梁,保存消息和分发消息,走向了subscribe/publish模式。

whiteboard

图摘抄至OSGi in Practice。这并无神奇的地方,只是把复杂的代码挪到了broker。OSGi则在这个地方加上了比如异步,有顺序的分发和可靠的分发这些功能。还有Topic的功能,比如有一个topic: a/b/c/*,这样event source和listener直接就靠这个纽带来进行交互,在Android中把这个抽象成URI,感觉几乎是一样的。

倒不清楚Android是一个OSGi的实现?还是只是把OSGi作为一个templete拿来模仿?