“你好,阿米戈!今天我會告訴你一些關於 BufferedInputStream 類的有趣的事情,但讓我們從 «包裝紙» 和一袋 «糖袋»開始。
“你所說的 «wrapper» 和 «bag of sugar» 是什麼意思?
“這些都是隱喻。聽著。所以……”
«wrapper»(或«decorator»)設計模式是一種相當簡單方便的機制,用於在不使用繼承的情況下擴展對像功能。

假設我們有一個帶有兩個方法的 Cat 類:getName 和 setName:
Java代碼 | 描述 |
---|---|
|
Cat 類有兩個方法:getName 和 setName |
|
一個如何使用它的例子。 «Oscar» 將顯示在控制台上。 |
假設我們需要攔截對cat對象的方法調用,並可能進行一些小的更改。為此,我們需要將其包裝在自己的包裝器類中。
如果我們想圍繞對某個對象的方法調用“包裝”我們自己的代碼,那麼我們需要:
1)創建我們自己的包裝類,繼承自與被包裝對象相同的類/接口。
2)將要包裝的對像傳遞給我們類的構造函數。
3)覆蓋我們新類中的所有方法。在每個覆蓋的方法中調用包裝對象的方法。
4)做任何你想做的改變:改變方法調用的作用,改變它們的參數,和/或做其他事情。
在下面的示例中,我們攔截了對 Cat 對象的 getName 方法的調用並稍微更改了它的返回值。
Java代碼 | 描述 |
---|---|
|
Cat 類包含兩個方法:getName 和setName。 |
|
包裝類。除了對原始對象的引用之外,該類不存儲任何數據。 該類能夠“拋出”對傳遞給構造函數的原始對象 (setName) 的調用。它還可以“捕獲”這些調用並修改它們的參數和/或結果。 |
|
一個如何使用它的例子。 «一隻名叫奧斯卡的貓»。 |
換句話說,我們悄悄地用包裝器對象替換每個原始對象,包裝器對象接收到原始對象的鏈接。包裝器上的所有方法調用都被轉發到原始對象,一切都像發條一樣運行。
“我喜歡。解決方案簡單實用。”
“我還要告訴你一個 «bag of sugar»。這是一個比喻,而不是設計模式。比喻緩沖和緩衝這個詞。什麼是緩衝,我們為什麼需要它?”

假設今天輪到 Rishi 做飯,而你正在幫助他。Rishi 還沒來,但我想喝茶。我請你給我一勺糖。你去地下室找到一袋糖。你可以把整個袋子都給我,但我不需要袋子。我只需要一勺。然後,像個好機器人一樣,你舀一勺給我。我把它加到茶裡,但還是不夠甜。我請你再給我帶一個。你再次去地下室再拿一勺。然後艾莉來了,我讓你給她拿糖來……這一切都太費時了,而且效率低下。
Rishi 來了,看到這一切,要你給他拿一個裝滿糖的糖罐。然後艾莉和我開始向里希要糖。他只是從糖罐裡端給我們,僅此而已。
Rishi 出現後發生的事情稱為緩衝:糖罐是一個緩衝。多虧了緩衝,“客戶端”可以從緩衝區中讀取一小部分數據,而緩衝區為了節省時間和精力,可以從源中讀取大部分數據。
“這是一個很酷的例子,Kim。我完全理解。請求一勺糖就像從流中讀取一個字節。”
“完全正確。BufferedInputStream類是緩衝包裝器的經典示例。它包裝了 InputStream 類。它以大塊的形式從原始 InputStream 中讀取數據到緩衝區中,然後在我們將數據逐個從緩衝區中取出時從中讀取。”
“很好,都清楚了,有寫緩衝區嗎?”
“哦沒問題。”
“也許是一個例子?”
“想像一個垃圾桶。不用每次都去外面把垃圾放進焚化爐,你只需把它扔進垃圾桶。然後 Bubba 每兩週把垃圾桶帶到外面一次。經典的緩衝。”

“多麼有趣!順便說一下,比一袋糖還要清楚得多。”
“而 flush() 方法就像立即取出垃圾一樣。您可以在客人到達之前使用它。”
GO TO FULL VERSION