"Bună ziua, Amigo! Astăzi vă voi spune câteva lucruri interesante despre clasa BufferedInputStream, dar să începem cu « ambalaje » și o « pungă de zahăr »."

„Ce vrei să spui prin „înveliș” și „pungă de zahăr”?”

"Acestea sunt metafore. Ascultă. Deci..."

Modelul de design „înveliș” (sau „decorator”) este un mecanism destul de simplu și convenabil pentru extinderea funcționalității obiectului fără a utiliza moștenirea.

BufferedInputStream - 1

Să presupunem că avem o clasă Cat cu două metode: getName și setName:

Cod Java Descriere
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;
 }
}
Clasa Cat are două metode: getName și 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());
}
Un exemplu despre cum ar putea fi folosit.

„Oscar” va fi afișat pe consolă.

Să presupunem că trebuie să interceptăm un apel de metodă pe un obiect pisică și poate să facem câteva mici modificări. Pentru aceasta, trebuie să -l ambalăm în propria sa clasă de ambalaje.

Dacă vrem să „împachetăm” propriul nostru cod în jurul apelurilor de metodă pe un obiect, atunci trebuie să:

1) Creați propria noastră clasă wrapper și moșteniți din aceeași clasă/interfață ca și obiectul care urmează să fie înfășurat.

2) Treceți obiectul de împachetat constructorului clasei noastre.

3) Suprascrieți toate metodele din noua noastră clasă. Invocați metodele obiectului împachetat în fiecare dintre metodele suprascrise.

4) Faceți orice modificări doriți: schimbați ceea ce face apelurile metodei, modificați parametrii acestora și/sau faceți altceva.

În exemplul de mai jos, interceptăm apelurile către metoda getName a unui obiect Cat și modificăm ușor valoarea returnată.

Cod Java Descriere
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;
 }
}
Clasa Cat conține două metode: getName și 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);
 }
}
Clasa de ambalare. Clasa nu stochează date cu excepția unei referințe la obiectul original.
Clasa este capabilă să „aruncă” apeluri către obiectul original (setName) transmis constructorului. De asemenea, poate „prinde” aceste apeluri și poate modifica parametrii și/sau rezultatele acestora .
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());
}
Un exemplu despre cum ar putea fi folosit.

„O pisică pe nume Oscar”.
va fi afișat pe consolă

Cu alte cuvinte, înlocuim în liniște fiecare obiect original cu un obiect de înveliș, care primește o legătură către obiectul original. Toate apelurile de metodă de pe wrapper sunt redirecționate către obiectul original și totul funcționează ca un ceas.

"Îmi place. Soluția este simplă și funcțională."

„Îți voi spune și despre o „pungă de zahăr”. Aceasta este mai degrabă o metaforă decât un model de design. O metaforă pentru cuvântul tampon și tamponare. Ce este tamponarea și de ce avem nevoie de ea?"

BufferedInputStream - 2

Să zicem că astăzi este rândul lui Rishi să gătească și tu îl ajuți. Rishi nu este încă aici, dar vreau să beau ceai. Vă rog să-mi aduceți o lingură de zahăr. Te duci la subsol și găsești o pungă de zahăr. Îmi poți aduce toată geanta, dar nu am nevoie de geanta. Am nevoie doar de o lingură. Apoi, ca un robot bun, iei o lingură și mi-o aduci. Il adaug in ceai, dar tot nu este suficient de dulce. Și vă rog să-mi mai aduceți unul. Te duci din nou la subsol și aduci încă o lingură. Apoi vine Ellie și te rog să-i aduci zahăr... Toate astea durează prea mult și sunt ineficiente.

Rishi vine, vede toate astea și îți cere să-i aduci un vas de zahăr plin cu zahăr. Apoi Ellie și cu mine începem să-i cerem lui Rishi zahăr. Pur și simplu ni-l servește din vasul de zahăr și atât.

Ceea ce s-a întâmplat după ce a apărut Rishi se numește tamponare : bolul de zahăr este un tampon. Datorită tamponării, „clienții” pot citi datele dintr-un buffer în porțiuni mici , în timp ce bufferul, pentru a economisi timp și efort, le citește din sursă în porțiuni mari .

— Ăsta e un exemplu grozav, Kim. Înțeleg perfect. Cererea pentru o lingură de zahăr este ca și cum ai citi un octet dintr-un flux.

„Exact. Clasa BufferedInputStream este un exemplu clasic de wrapper cu buffer. Încheie clasa InputStream. Citește datele din InputStream original în blocuri mari într-un buffer, apoi le scoate din buffer bucată cu bucată, în timp ce noi citeste din ea.”

"Foarte bine. Totul este clar. Există tampoane pentru scris?"

— Oh, sigur.

— Poate un exemplu?

"Imaginați-vă un coș de gunoi. În loc să ieși afară să arunci gunoiul într-un incinerator de fiecare dată, îl arunci doar în coșul de gunoi. Apoi Bubba scoate coșul afară o dată la două săptămâni. Un tampon clasic."

"Ce interesant! Și mult mai clar decât o pungă de zahăr, apropo."

„Și metoda flush() este ca și cum scoateți gunoiul imediat. O puteți folosi înainte de sosirea oaspeților”.