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 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(...) の途中で発生するため、もう一度 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

いくつかの試行と失敗の後、すべての実装メソッドを「最終」にする以外に選択肢はありません。コールバックのみを保護し、サブクラス化したままにします。

とにかく、ここにソースを置きます。まだアルファ版です。現在、パフォーマンスのチューニングに取り組んでいます。

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 に答える