“你好,阿米戈!今天我會告訴你一些關於 BufferedInputStream 類的有趣的事情,但讓我們從 «包裝紙» 和一袋 «糖袋»開始。

“你所說的 «wrapper» 和 «bag of sugar» 是什麼意思?

“這些都是隱喻。聽著。所以……”

«wrapper»(或«decorator»)設計模式是一種相當簡單方便的機制,用於在不使用繼承的情況下擴展對像功能。

緩衝輸入流 - 1

假設我們有一個帶有兩個方法的 Cat 類:getName 和 setName:

Java代碼 描述
class Cat
{
 private String name;
 public Cat(String name)
 {
  this.name = name;
 }
 public String getName()
 {
  return this.name;
 }
 public void setName(String name)
 {
  this.name = name;
 }
}
Cat 類有兩個方法:getName 和 setName
public static void main(String[] args)
{
 Cat cat = new Cat("Oscar");

 printName(cat);
}

public static void printName(Cat cat)
{
 System.out.println(cat.getName());
}
一個如何使用它的例子。

«Oscar» 將顯示在控制台上。

假設我們需要攔截對cat對象的方法調用,並可能進行一些小的更改。為此,我們需要將其包裝在自己的包裝器類中。

如果我們想圍繞對某個對象的方法調用“包裝”我們自己的代碼,那麼我們需要:

1)創建我們自己的包裝類,繼承自與被包裝對象相同的類/接口。

2)將要包裝的對像傳遞給我們類的構造函數。

3)覆蓋我們新類中的所有方法。在每個覆蓋的方法中調用包裝對象的方法。

4)做任何你想做的改變:改變方法調用的作用,改變它們的參數,和/或做其他事情。

在下面的示例中,我們攔截了對 Cat 對象的 getName 方法的調用並稍微更改了它的返回值。

Java代碼 描述
class Cat
{
 private String name;
 public Cat(String name)
 {
  this.name = name;
 }
 public String getName()
 {
  return this.name;
 }
 public void setName(String name)
 {
  this.name = name;
 }
}
Cat 類包含兩個方法:getName 和setName。
class CatWrapper extends Cat
{
 private Cat original;
 public CatWrapper (Cat cat)
 {
  super(cat.getName());
  this.original = cat;
 }

 public String getName()
 {
  return "A cat named " + original.getName();
 }

 public void setName(String name)
 {
  original.setName(name);
 }
}
包裝類。除了對原始對象的引用之外,該類不存儲任何數據。
該類能夠“拋出”對傳遞給構造函數的原始對象 (setName) 的調用。它還可以“捕獲”這些調用並修改它們的參數和/或結果
public static void main(String[] args)
{
 Cat cat = new Cat("Oscar");
 Cat catWrap = new CatWrapper (cat);
 printName(catWrap);
}

public static void printName(Cat named)
{
 System.out.println(named.getName());
}
一個如何使用它的例子。

«一隻名叫奧斯卡的貓»。
會顯示在控制台

換句話說,我們悄悄地用包裝器對象替換每個原始對象,包裝器對象接收到原始對象的鏈接。包裝器上的所有方法調用都被轉發到原始對象,一切都像發條一樣運行。

“我喜歡。解決方案簡單實用。”

“我還要告訴你一個 «bag of sugar»。這是一個比喻,而不是設計模式。比喻緩沖和緩衝這個詞。什麼是緩衝,我們為什麼需要它?”

緩衝輸入流 - 2

假設今天輪到 Rishi 做飯,而你正在幫助他。Rishi 還沒來,但我想喝茶。我請你給我一勺糖。你去地下室找到一袋糖。你可以把整個袋子都給我,但我不需要袋子。我只需要一勺。然後,像個好機器人一樣,你舀一勺給我。我把它加到茶裡,但還是不夠甜。我請你再給我帶一個。你再次去地下室再拿一勺。然後艾莉來了,我讓你給她拿糖來……這一切都太費時了,而且效率低下。

Rishi 來了,看到這一切,要你給他拿一個裝滿糖的糖罐。然後艾莉和我開始向里希要糖。他只是從糖罐裡端給我們,僅此而已。

Rishi 出現後發生的事情稱為緩衝:糖罐是一個緩衝。多虧了緩衝,“客戶端”可以從緩衝區中讀取一小部分數據,而緩衝區為了節省時間和精力,可以從源中讀取大部分數據

“這是一個很酷的例子,Kim。我完全理解。請求一勺糖就像從流中讀取一個字節。”

“完全正確。BufferedInputStream是緩衝包裝器的經典示例。它包裝了 InputStream 類。它以大塊的形式從原始 InputStream 中讀取數據到緩衝區中,然後在我們將數據逐個從緩衝區中取出時從中讀取。”

“很好,都清楚了,有寫緩衝區嗎?”

“哦沒問題。”

“也許是一個例子?”

“想像一個垃圾桶。不用每次都去外面把垃圾放進焚化爐,你只需把它扔進垃圾桶。然後 Bubba 每兩週把垃圾桶帶到外面一次。經典的緩衝。”

“多麼有趣!順便說一下,比一袋糖還要清楚得多。”

“而 flush() 方法就像立即取出垃圾一樣。您可以在客人到達之前使用它。”