郁闷, refactor遇到死胡同。
我有一个接口Pool, 如下: public interface Pool{ Worker getWorker(); } 用来从池中取得一个Worker对象。Worker的接口是: public interface Worker{ public void start(Runnable r); } 另外有一个接口PoolOwner, 作为一个Pool的拥有者,可以对Pool进行清理,关闭等操作 public interface PoolOwner extends Pool{ public void close(); ... } 现在,一个异步任务处理模块需要使用Pool对象。同时,我不想让这个任务处理模块拥有Pool对象的所有权,因为,多个不同的模块可能要共享一个Pool. 可是,我又需要保证Pool对象在不用时被关掉。依赖finalize当然是不好的了。
所以,这里,我引入了引用计数的机制: 一个Referent接口,代表计数server, 它应当拥有一个Pool的所有权。 public interface Referent{ public void enref(); public void deref(); public Pool get(); } 一个线程安全的实现代码是: final class ReferentImpl implements Referent{ public synchronized void enref(){++count;} public synchronized void deref(){ if(--count<=0)pool.close(); } public Pool get(){return pool;} private final PoolOwner pool; private int count=1; private ReferentImpl(final PoolOwner p){this.pool = p;} static Referent instance(final PoolOwner p){return ReferentImpl(p);} }
此外,我们还需要一个代表引用计数客户的借口。 public interface Ref extends Pool{ public Ref enref(); public void release(); } 这里,对客户端的考虑是: 1。 绝对不允许一个Ref对象把Referent的计数递减两次。否则,一个客户的失误就又可能影响到其它客户的工作。 enref将生成一个新的客户,而旧的客户仍然只需调用release一次。 我的实现是这样: 首先,做一个null reference.
final class NilReferent implements Referent{ public void enref(){ throw new NilRefException(); } public void deref(){} public Pool get(){throw new NilRefException();} ...//这里,做一个singleton. } 然后: final class RefImpl implements Ref{ public Ref enref(){ ref.enref(); return instance(ref); } public void release(){ ref.deref(); ref = NilReferent.instance(); } public Worker get(){ return ref.get().getWorker(); } protected final void finalize(){ref.deref();} private RefImpl (final Referent r){this.ref = r;} static Ref instance(Referent r){return new RefImpl(r);} }
测试的代码如下: PoolOwner pool = ......; final Ref r1 = RefImpl.instance(ReferentImpl.instance(pool)); final Ref r2 = r1.enref(); r1.get(); r1.release();//释放r1 r2.get();//这里,r2可以工作 r1.release();//抛出异常,r1已经调用过一次release r2.get();//r2仍然可以照常工作 r2.release();//这里,计数减到0, pool会被Referent关闭 r2.get();//抛出异常,r2已经release了。
好,到此,一切都很好。但接下来。。。
我还有一个接口Processor public interface Processor extends Worker{ public void interrupt(); } 这个Processor提供中断的功能,因此,会要求实现者更复杂的逻辑,而且会有一定的效率上的代价。 有了Processor, 就有ProcessorPool public interface ProcessorPool{ public Processor getProcessor(); } ok, 我也实现了Processor和ProcessorPool. 以及,很自然的ProcessorPoolOwner: public interface ProcessorPoolOwner extends ProcessorPool{ public void close(); }
好啦,现在,如果我也要实现以上的引用计数逻辑,怎么办? 有什么好办法可以不用copy&paste呢?感觉象到了死胡同啊!

|