次のシナリオを想定します。
XmlParser1
メソッドを公開するXMLパーサーなど、バイトストリームを消費するライブラリのJavaクラスがありますxmlParser1.parse(inputStream)
。このメソッドは通常、1 回の呼び出しですべてのバイトを消費し、最終的にブロックします。XmlParser2
また、別のライブラリから、実装が 異なる、似たようなことを行う別のクラスもありますxmlParser2.parse(inputStream)
。ここで、両方のパーサーで単一のストリームを解析したいと考えています。
私の最初の答えは次のとおりです。各クラスがストリームをどのように消費するかを制御することはできないため、できることはすべてのバイトをメモリ内または一時ファイルにバッファリングする (または可能であれば開く/再度開く) ことだけです。これらのコンシューマーの API は、本質的に非協調的です。
ここで、XmlParser1
(実装と署名) を制御し、呼び出し元が上記の動作を合理的かつ効率的な方法で実装できるように、より柔軟で協調的な方法でコーディングしたいとします... 何を提案しますか?
私が検討しているいくつかの代替案:
1) をXmlParser1
実装FilterInputStream
して、一部のクラス ( XmlParser1
) がそこからバイトを読み込もうとすると、必要なものを内部的に解析し (反復的に、おそらく合理的なバッファリングを使用して)、生のバイトを返すようにします。FilterInputStream
(これはコンセプトと正確には一致しません)。このようにして、クライアント コードはパーサーを単純に連鎖させることができます。
public class XmlParser1 extends FilterInputStream {
public XmlParser1(InputStream rawInputStream) { ... }
public int read(byte[] b, int off, int l) throws IOException {
// this would invoke the underlying stream read, parse internall the read bytes,
// and leave them in the buffer
}
}
XmlParser1 parser1 = new XmlParser1(inputstream);
XmlParser2 parser2 = new XmlParser2(parse);
parser2.parse(); // parser2 consumes all the input stream, which causes parser1 to read an parse it too
XmlParser1
2) at をバイトの消費者と見なす代わりに、シンクと見なします。バイト自体を食べさせず、スプーンで供給します。つまり、... を渡す代わりに、 をxmlParser1.parse(inputStream)
渡し
ます。これにより、クライアントは、バイトを透過的にクラスに渡し、同時に呼び出しを行う TeeInputStream を作成できます。xmlParser1.write(byte[])
InputStream
OutputStream
XmlParser2
XmlParser1.write()
いずれの場合も個別のスレッドは必要ないことに注意してください。
より良い代替案があるかどうかについて、どちらが概念的に好ましいかはわかりません。すでに議論されているはずの設計上の問題のように思えますが、必ずしもJavaに限定されているわけではありません。意見や参考文献を歓迎します。