"Hej, Amigo! I dag vil jeg fortælle dig et par interessante ting om BufferedInputStream-klassen, men lad os starte med " indpakninger " og en " pose sukker ".

"Hvad mener du med "indpakning" og "pose sukker"?"

"Det er metaforer. Hør her. Så..."

«Wrapper» (eller «decorator») designmønster er en ret enkel og bekvem mekanisme til at udvide objektfunktionaliteten uden at bruge arv.

BufferedInputStream - 1

Antag, at vi har en Cat-klasse med to metoder: getName og setName:

Java kode Beskrivelse
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-klassen har to metoder: getName og 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());
}
Et eksempel på hvordan det kan bruges.

"Oscar" vil blive vist på konsollen.

Antag, at vi skal opsnappe et metodekald på et katteobjekt og måske lave nogle små ændringer. Til dette skal vi pakke den ind i sin egen indpakningsklasse.

Hvis vi vil "pakke" vores egen kode omkring metodekaldene på et eller andet objekt, så skal vi:

1) Opret vores egen wrapper-klasse og arv fra samme klasse/grænseflade som objektet, der skal indpakkes.

2) Send objektet, der skal indpakkes, til vores klasses konstruktør.

3) Tilsidesæt alle metoder i vores nye klasse. Kald det indpakkede objekts metoder inde i hver af de tilsidesatte metoder.

4) Foretag de ændringer, du vil: ændre, hvad metodekaldene gør, ændre deres parametre og/eller gøre noget andet.

I eksemplet nedenfor opsnapper vi kald til et Cat-objekts getName-metode og ændrer en smule dets returværdi.

Java kode Beskrivelse
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-klassen indeholder to metoder: getName og 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);
 }
}
Indpakningsklassen. Klassen gemmer ingen data undtagen en reference til det originale objekt.
Klassen er i stand til at "kaste" kald til det originale objekt (setName), der er sendt til konstruktøren. Det kan også "fange" disse opkald og ændre deres parametre og/eller resultater .
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());
}
Et eksempel på hvordan det kan bruges.

"En kat ved navn Oscar".
vil blive vist på konsollen

Med andre ord erstatter vi stille og roligt hvert originalt objekt med et indpakningsobjekt, som modtager et link til det originale objekt. Alle metodekald på wrapperen videresendes til det originale objekt, og alt kører som smurt.

"Jeg kan godt lide det. Løsningen er enkel og funktionel."

"Jeg vil også fortælle dig om en "pose sukker". Dette er en metafor snarere end et designmønster. En metafor for ordet buffer og buffering. Hvad er buffering, og hvorfor har vi brug for det?"

BufferedInputStream - 2

Lad os sige, at i dag er det Rishis tur til at lave mad, og du hjælper ham. Rishi er her ikke endnu, men jeg vil gerne drikke te. Jeg beder dig om at bringe mig en skefuld sukker. Du går i kælderen og finder en pose sukker. Du kan medbringe hele posen til mig, men jeg har ikke brug for posen. Jeg mangler kun en skefuld. Så, som en god robot, tager du en skefuld og bringer den til mig. Jeg tilføjer det til teen, men det er stadig ikke sødt nok. Og jeg beder dig bringe mig en mere. Du går igen i kælderen og medbringer endnu en skefuld. Så kommer Ellie, og jeg beder dig om at tage sukker med til hende... Alt dette tager for lang tid og er ineffektivt.

Rishi kommer, ser alt dette og beder dig bringe ham en sukkerskål fuld af sukker. Så begynder Ellie og jeg at bede Rishi om sukker. Han serverer det simpelthen for os fra sukkerskålen, og det er det hele.

Det, der skete, efter at Rishi dukkede op, kaldes buffering : sukkerskålen er en buffer. Takket være buffering kan "klienter" læse data fra en buffer i små portioner , mens bufferen, for at spare tid og kræfter, læser dem fra kilden i store portioner .

"Det er et sejt eksempel, Kim. Jeg forstår det godt. Anmodningen om en skefuld sukker er som at læse en byte fra en strøm."

"Nøjagtigt. BufferedInputStream- klassen er et klassisk eksempel på en buffer-indpakning. Den ombryder InputStream-klassen. Den læser data fra den originale InputStream i store blokke ind i en buffer, og trækker den derefter ud af bufferen stykke-for-stykke, efterhånden som vi læs fra det."

"Meget godt. Det hele er klart. Er der buffere til at skrive?"

"Helt sikkert."

"Måske et eksempel?"

"Forestil dig en skraldespand. I stedet for at gå udenfor for at lægge affald i et forbrændingsanlæg hver gang, smider du det bare i skraldespanden. Så tager Bubba dåsen udenfor en gang hver anden uge. En klassisk buffer."

"Hvor interessant! Og i øvrigt meget klarere end en pose sukker."

"Og flush()-metoden er som at tage skraldet ud med det samme. Du kan bruge det, før gæster ankommer."