"Hej, Amigo! Idag ska jag berätta några intressanta saker om BufferedInputStream-klassen, men låt oss börja med " omslag " och en " påse socker ".

"Vad menar du med "omslag" och "påse socker"?"

"Det här är metaforer. Lyssna. Så..."

Designmönstret «omslag» (eller «dekoratör») är en ganska enkel och bekväm mekanism för att utöka objektfunktionaliteten utan att använda arv.

BufferedInputStream - 1

Anta att vi har en Cat-klass med två metoder: getName och setName:

Java-kod Beskrivning
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 två metoder: getName och 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());
}
Ett exempel på hur det kan användas.

«Oscar» kommer att visas på konsolen.

Anta att vi behöver avlyssna ett metodanrop på ett kattobjekt och kanske göra några små ändringar. För detta måste vi slå in den i en egen omslagsklass.

Om vi ​​vill "linda" vår egen kod runt metodanropen på något objekt, måste vi:

1) Skapa vår egen wrapper-klass och ärv från samma klass/gränssnitt som objektet som ska wrappas.

2) Skicka objektet som ska packas till vår klasss konstruktor.

3) Åsidosätt alla metoder i vår nya klass. Anropa det lindade objektets metoder inuti var och en av de åsidosatta metoderna.

4) Gör vilka ändringar du vill: ändra vad metodanropen gör, ändra deras parametrar och/eller gör något annat.

I exemplet nedan avlyssnar vi anrop till ett Cat-objekts getName-metod och ändrar dess returvärde något.

Java-kod Beskrivning
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 innehåller två metoder: getName och 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);
 }
}
Omslagsklassen. Klassen lagrar ingen data förutom en referens till det ursprungliga objektet.
Klassen kan "kasta" anrop till det ursprungliga objektet (setName) som skickats till konstruktorn. Den kan också "fånga" dessa anrop och ändra deras parametrar och/eller resultat .
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());
}
Ett exempel på hur det kan användas.

"En katt som heter Oscar".
kommer att visas på konsolen

Med andra ord ersätter vi tyst varje originalobjekt med ett omslagsobjekt, som får en länk till originalobjektet. Alla metodanrop på omslaget vidarebefordras till det ursprungliga objektet och allt går som en klocka.

"Jag gillar det. Lösningen är enkel och funktionell."

"Jag ska också berätta om en «påse socker». Det här är en metafor snarare än ett designmönster. En metafor för ordet buffert och buffert. Vad är buffert och varför behöver vi det?"

BufferedInputStream - 2

Låt oss säga att idag är det Rishis tur att laga mat, och du hjälper honom. Rishi är inte här än, men jag vill dricka te. Jag ber dig att ge mig en sked socker. Du går till källaren och hittar en påse socker. Du kan ta med mig hela väskan, men jag behöver inte väskan. Jag behöver bara en sked. Sedan, som en bra robot, tar du en sked och tar med den till mig. Jag lägger till det i teet, men det är fortfarande inte tillräckligt sött. Och jag ber dig att ta med mig en till. Du går igen till källaren och tar med en sked till. Sedan kommer Ellie och jag ber dig ta med socker till henne... Allt detta tar för lång tid och är ineffektivt.

Rishi kommer, ser allt detta och ber dig att ge honom en sockerskål full med socker. Sedan börjar jag och Ellie be Rishi om socker. Han serverar det helt enkelt till oss från sockerskålen, och det är allt.

Det som hände efter att Rishi dök upp kallas buffring : sockerskålen är en buffert. Tack vare buffring kan "klienter" läsa data från en buffert i små portioner , medan bufferten, för att spara tid och ansträngning, läser dem från källan i stora portioner .

"Det är ett coolt exempel, Kim. Jag förstår perfekt. Begäran om en sked socker är som att läsa en byte från en ström."

"Precis. Klassen BufferedInputStream är ett klassiskt exempel på ett buffrat omslag. Den lindar InputStream-klassen. Den läser data från den ursprungliga InputStream i stora block till en buffert, och drar sedan ut den ur bufferten bit för bit när vi läs från den."

"Mycket bra. Allt är klart. Finns det buffertar för att skriva?"

"Åh visst."

"Kanske ett exempel?"

"Föreställ dig en soptunna. Istället för att gå ut och lägga skräp i en förbränningsugn varje gång, slänger du det bara i papperskorgen. Då tar Bubba ut burken en gång varannan vecka. En klassisk buffert."

"Vad intressant! Och mycket klarare än en påse socker, förresten."

"Och metoden flush() är som att ta ut skräpet direkt. Du kan använda den innan gästerna kommer."