假設以下情形:合作流消費者的設計理念?
我們已經從消耗字節流的一些庫的Java類,說一些XML解析器XmlParser1
暴露的方法xmlParser1.parse(inputStream)
;該方法通常會在一次調用中吃掉所有字節,最終會被阻塞。 我們還有另外一類,來自其他一些庫,類似地做了不同的實現:XmlParser2
和xmlParser2.parse(inputStream)
。 現在,我們想要用兩個解析器解析單個流。
我的第一個答案是:我們搞砸了。由於我們無法控制每個類如何消耗流,因此我們只能緩衝內存中的所有字節或臨時文件(如果可能,請打開/重新打開它)。這些消費者的API本質上是不合作的。
現在,假設我們對XmlParser1
(實現和簽名)有控制權,並且我們希望以更靈活和合作的方式對其進行編碼,以便調用者可以以一種合理和有效的方式實現上述行爲......你會建議嗎?
一些替代方案,我考慮:
1)請XmlParser1
實施FilterInputStream
,這樣,當某一類(XmlParser1
)attemps來讀取它的一些字節,它在內部解析它具有(迭代,也許一些合理的緩衝)並且還返回原始字節。 (這並不完全對應於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
2)而不是在字節XmlParser1
爲消費者有關的,把它當成一個沉:我們不會讓它吃本身就是字節,我們將用它來填充。所以,相反的xmlParser1.parse(inputStream)
我們可以有 xmlParser1.write(byte[])
...也就是說,而不是傳遞一個InputStream
我們會做一個OutputStream
。這將允許客戶端創建一個TeeInputStream,將字節透明地傳遞給XmlParser2
類,並且同時調用XmlParser1.write()
請注意,我們在任何情況下都不需要單獨的線程。
我不確定哪一個(如果有的話)在概念上更可取,如果有更好的選擇。這聽起來像是一個應該已經討論過的設計問題,但我沒有發現太多東西 - 不一定只限於Java。歡迎意見和參考。
也檢查PipeInputStream/PipeOutputStream類。 –
您如何看待我的回答?我只是問,因爲我爲您提供了最乾淨的解決方案:使對象脫離流,然後處理對象。但是我也知道另一個解決方案,比方說一個「解決方法」,我認爲這不是最好的實現方式,而只是一種可能的解決方案。不過,我不知道你爲什麼要多次解析同一個流,因爲這會消耗CPU的能力。但是,我也不知道你的實現,可能存在一些罕見的特殊情況,這樣做是適當的。你能告訴我們更多一點嗎?爲什麼你想分析兩次相同的流? – Marcus
@Marcus:假設我更喜歡XmlParser2,但XmlParser1給了我一些附加信息。我的具體情況是:我有一個我想用的PngReader2(因爲它直接給我我想要的圖像格式),而且還有一個解析元數據的PngReader1,我希望這兩件事情都是。 – leonbloy