0

我想建立一个多层缓冲区:

public class Buffer{
    protected void onReadComplete(int read){
        //...
        // throw new RuntimeException(...);
    }
    public void read(...){
        //...
        //...
        onReadCompleted(some);// we can throw RuntimeExceptions here without corrupt the field mAlreadyRead.
        mAlreadyRead+=some;
        return;
    }
    protected void checkRead(...) throws Exception{
        //...
    }
}

在第一层(子类)中,您可以这样做:

Buffer lowlevel=new Buffer(){
    @Override
    protected void onReadComplete(int read){
        super.onReadComplete(read);
        //...
    }
    @Override
    Protected void checkRead(){
        //...
    }
};

然后,每当访问实例 lowlevel 时,您将通过覆盖的 lowlevel.onReadComplete 例程获得通知。但后来我想将此缓冲区传递给我程序的另一部分。这里的问题是“我的程序的另一部分”不能只新建一个实例并覆盖 Buffer 中的方法,它只获取 Buffer 的一个实例。如何覆盖该实例中的方法以添加更多层?我想要的是:

Buffer higherLevel=lowlevel{
    @Override
    protected void onReadComplete(int read){
        super.onReadComplete(read);
        //...
    }
}

但是当然java不会让我知道......

但是,java 确实提供了 Proxy。但我希望有一种干净、统一、低开销、关注性能的方式来做到这一点。

而且我们不能添加回调接口:

public class BufferWrapper{
    IEventBuffer event;
    public read(...){
        //...
        event.onReadComplete(...);
        //...
    }
    public BufferWrapper(Buffer buffer,IEventBuffer event){
        buffer.event=event;
    }
}

当通过higherLevel访问时,我们在两者上都触发onReadComplete,但是当通过lowlevel访问时,我们只触发lowlevel.onReadComplete。

我们不能使用这种方法:

Buffer higherLevel=new Buffer(lowlevel){
    @Override
    protected void onReadComplete(int read){
        super.onReadComplete(read);
        //...
    }
}

因为 onReadComplete 发生在 read(...) 的中间,我不想再次实现读取。

请原谅我的英语不好,我不知道我是否表达了我的观点:

...我已经制作了插图图片,但我无法发布图片... -->a 表示通过实例 a 访问

<pre>
-->lo---------------------------------->lo.onXXX
---------->  hi1-->hi1.onXXX----------->lo.onXXX
---------->  hi2-->hi2.onXXX----------->lo.onXXX
-->  hi3-->  hi2-->  hi3.onXXX,hi2.onXXX->lo.onXXX
</pre>
4

1 回答 1

0

经过一些尝试和失败后,我别无选择,只能“最终”所有实现方法。只保留受保护和子类化的回调。

无论如何,我会把源代码放在这里。它仍然是一个 alpha 版本,我现在正在进行一些性能调整。

public class Buffer {
    private class BufferImpl{
        public int mCapacity;
        public int mMask;
        public byte[] mBacking;
        public long mRead,mWrite;
        @Override
        public String toString() {
            int ca=mCapacity;
            char[] cs=new char[ca+ca+ca+2];
            for(int i=0;i<cs.length;i++)
                cs[i]=' ';
            byte[] bk=mBacking;
            cs[ca]='\n';
            cs[ca+ca+1]='\n';
            for(int i=0;i<ca;i++)
                cs[i]=bk[i]=='\n'||bk[i]=='\r'?'.':(char)bk[i];
            int r=(int)mRead&mMask;
            int w=(int)mWrite&mMask;
            if(mRead==mWrite)return new String(cs);
            if(r<w){
                for(int i=r;i<w;i++)
                    cs[i+ca+1]=bk[i]=='\n'||bk[i]=='\r'?'.':(char)bk[i];
                return new String(cs);
            }else{
                for(int i=r;i<ca;i++)
                    cs[i+ca+1]=bk[i]=='\n'||bk[i]=='\r'?'.':(char)bk[i];
                for(int i=0;i<w;i++)
                    cs[i+ca+ca+2]=bk[i]=='\n'||bk[i]=='\r'?'.':(char)bk[i];
                return new String(cs);
            }
        }
        public BufferImpl(int capacity){
            checkAndSetCapacity(capacity);
            mBacking=new byte[capacity];
        }
        public BufferImpl(byte[] backing){
            checkAndSetCapacity(backing.length);
            mBacking=backing;
        }
        private void checkAndSetCapacity(int capacity){
            if((mMask&capacity)!=0)
                throw new IllegalArgumentException("capacity "+capacity+" is not a power of 2");
            mMask=capacity-1;
            mCapacity=capacity;
        }
    }
    private BufferImpl impl;
    private Buffer lower;
    @Override
    public String toString() {
        return impl.toString();
    }
    public Buffer(int capacity){
        impl=new BufferImpl(capacity);
    }
    public Buffer(byte[] backing){
        impl=new BufferImpl(backing);
    }
    public Buffer(Buffer lower){
        this.lower=lower;
        this.impl=lower.impl;
    }

    public int availableRead(){
        if(lower!=null)
            return lower.availableRead();
        return (int)(impl.mWrite-impl.mRead);
    }
    public int availableWrite(){
        if(lower!=null)
            return lower.availableWrite();
        return capacity()-(int)(impl.mWrite-impl.mRead);
    }
    public int capacity(){
        if(lower!=null)
            return lower.capacity();
        return impl.mCapacity;
    }
    protected void onReset(){
        if(lower!=null)
            lower.onReset();
    }
    public final void reset(){
        onReset();
        impl.mRead=impl.mWrite=0;
    }
    protected void onReadComplete(int read){
        if(lower!=null)
            lower.onReadComplete(read);
    }
    public final void confirmRead(int read){
        onReadComplete(read);
        impl.mRead+=read;
    }
    public final int peek(byte[] out, int offset, int length){
        if(length==-1) length=out.length-offset;
        int effectiveLen=availableRead();
        if(length<effectiveLen) effectiveLen=length;
        if(effectiveLen>0){
            byte[] backing=impl.mBacking;
            int pos=(int)(impl.mRead & impl.mMask);
            int capacity=capacity();
            if(pos+effectiveLen>capacity){
                int left=effectiveLen-(capacity-pos);
                do{out[offset++]=backing[pos++];
                }while(pos<capacity);pos=0;
                do{out[offset++]=backing[pos++];
                }while(pos<left);
            }else{
                int lim=pos+effectiveLen;
                do{out[offset++]=backing[pos++];
                }while(pos<lim);
            }
        }return effectiveLen;
    }
    public final int peek(Buffer out, int length){
        if(length==-1) length=out.availableWrite();
        int effectiveLen=availableRead();
        if(length<effectiveLen) effectiveLen=length;
        if(effectiveLen>0){
            byte[] backing=impl.mBacking;
            int pos=(int)(impl.mRead & impl.mMask);
            int capacity=capacity();
            if(pos+effectiveLen>capacity){
                int p1=capacity-pos;
                int p2=effectiveLen-p1;
                out.write(backing, pos, p1);
                out.write(backing, 0, p2);
            }else out.write(backing, pos, effectiveLen);
        }return effectiveLen;
    }
    public final int read(byte[] out, int offset, int length){
        int len=peek(out, offset, length);
        confirmRead(len);
        return len;
    }
    public final int read(Buffer out, int length){
        int len=peek(out, length);
        confirmRead(len);
        return len;
    }
    protected void onWriteComplete(int written){
        if(lower!=null)
            lower.onWriteComplete(written);
    }
    public final int write(byte[] in, int offset, int length){
        if(length==-1) length=in.length-offset;
        int effectiveLen=availableWrite();
        if(length<effectiveLen) effectiveLen=length;
        if(effectiveLen>0){
            byte[] backing=impl.mBacking;
            int pos=(int)(impl.mWrite & impl.mMask);
            int capacity=capacity();
            if(pos+effectiveLen>capacity){
                int left=effectiveLen-(capacity-pos);
                do{backing[pos++]=in[offset++];
                }while(pos<capacity);pos=0;
                do{backing[pos++]=in[offset++];
                }while(pos<left);
            }else{
                int lim=pos+effectiveLen;
                do{backing[pos++]=in[offset++];
                }while(pos<lim);
            }onWriteComplete(effectiveLen);
            impl.mWrite+=effectiveLen;
            return effectiveLen;
        }onWriteComplete(effectiveLen);
        return effectiveLen;
    }
    public static void main(String[] args) {
        Buffer lower=new Buffer(16){
            @Override
            protected void onWriteComplete(int written) {
                System.out.println("lower.onWriteComplete  "+written);
                super.onWriteComplete(written);
            }
        };
        Buffer higher=new Buffer(lower){
            @Override
            protected void onWriteComplete(int written) {
                System.out.println("higher.onWriteComplete "+written);
                super.onWriteComplete(written);
            }
        };
        higher.write(new byte[0], 0, -1);
    }
}
于 2013-09-30T16:49:34.017 回答