"Halo, Amigo! Hari ini saya akan memberi tahu Anda beberapa hal menarik tentang kelas BufferedInputStream, tapi mari kita mulai dengan « pembungkus » dan « kantong gula »."

"Apa maksudmu dengan «pembungkus» dan «kantong gula»?"

"Ini adalah metafora. Dengar. Jadi..."

Pola desain «pembungkus» (atau «dekorator») adalah mekanisme yang cukup sederhana dan nyaman untuk memperluas fungsionalitas objek tanpa menggunakan pewarisan.

BufferedInputStream - 1

Misalkan kita memiliki kelas Cat dengan dua metode: getName dan setName:

kode jawa Keterangan
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;
 }
}
Kelas Cat memiliki dua metode: getName dan 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());
}
Contoh bagaimana itu bisa digunakan.

«Oscar» akan ditampilkan di konsol.

Misalkan kita perlu mencegat pemanggilan metode pada objek kucing dan mungkin membuat beberapa perubahan kecil. Untuk ini, kita perlu membungkusnya dalam kelas pembungkusnya sendiri.

Jika kita ingin "membungkus" kode kita sendiri di sekitar pemanggilan metode pada beberapa objek, maka kita perlu:

1) Buat kelas pembungkus kita sendiri dan mewarisi dari kelas/antarmuka yang sama dengan objek yang akan dibungkus.

2) Berikan objek yang akan dibungkus ke konstruktor kelas kita.

3) Ganti semua metode di kelas baru kami. Panggil metode objek yang dibungkus di dalam setiap metode yang diganti.

4) Buat perubahan apa pun yang Anda inginkan: ubah apa yang dilakukan pemanggilan metode, ubah parameternya, dan/atau lakukan sesuatu yang lain.

Dalam contoh di bawah ini, kami mencegat panggilan ke metode getName objek Cat dan sedikit mengubah nilai pengembaliannya.

kode jawa Keterangan
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;
 }
}
Kelas Cat berisi dua metode: getName dan 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);
 }
}
Kelas pembungkus. Kelas tidak menyimpan data apa pun kecuali referensi ke objek asli.
Kelas dapat "melempar" panggilan ke objek asli (setName) yang diteruskan ke konstruktor. Itu juga dapat "menangkap" panggilan ini dan mengubah parameter dan/atau hasil mereka .
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());
}
Contoh bagaimana itu bisa digunakan.

«Seekor kucing bernama Oscar».
akan ditampilkan di konsol

Dengan kata lain, kami secara diam-diam mengganti setiap objek asli dengan objek pembungkus, yang menerima tautan ke objek asli. Semua pemanggilan metode pada pembungkus diteruskan ke objek aslinya, dan semuanya berjalan seperti jarum jam.

"Saya menyukainya. Solusinya sederhana dan fungsional."

"Saya juga akan memberi tahu Anda tentang «kantong gula». Ini adalah metafora, bukan pola desain. Metafora untuk kata buffer dan buffering. Apa itu buffering dan mengapa kita membutuhkannya?"

BufferedInputStream - 2

Katakanlah hari ini giliran Rishi untuk memasak, dan Anda membantunya. Rishi belum datang, tapi aku ingin minum teh. Saya meminta Anda untuk membawakan saya sesendok gula. Anda pergi ke ruang bawah tanah dan menemukan sekantong gula. Anda dapat membawakan saya seluruh tas, tetapi saya tidak membutuhkan tas itu. Saya hanya butuh satu sendok. Kemudian, seperti robot yang baik, Anda mengambil satu sendok dan memberikannya kepada saya. Saya menambahkannya ke dalam teh, tetapi masih kurang manis. Dan saya meminta Anda untuk membawakan saya satu lagi. Anda kembali ke ruang bawah tanah dan membawa sesendok lagi. Lalu Ellie datang, dan aku memintamu membawakan gula untuknya... Semua ini memakan waktu terlalu lama dan tidak efisien.

Rishi datang, melihat semua ini, dan memintamu untuk membawakannya semangkuk gula penuh gula. Kemudian Ellie dan aku mulai meminta gula dari Rishi. Dia hanya menyajikannya kepada kami dari mangkuk gula, dan itu saja.

Apa yang terjadi setelah Rishi muncul disebut penyangga : mangkuk gula adalah penyangga. Berkat buffering, "klien" dapat membaca data dari buffer dalam porsi kecil , sedangkan buffer, untuk menghemat waktu dan tenaga, membacanya dari sumber dalam porsi besar .

"Itu contoh yang keren, Kim. Aku sangat mengerti. Permintaan sesendok gula seperti membaca satu byte dari sungai."

"Tepat. Kelas BufferedInputStream adalah contoh klasik dari buffered wrapper. Itu membungkus kelas InputStream. Ia membaca data dari InputStream asli dalam blok besar ke dalam buffer, dan kemudian menariknya keluar dari buffer sepotong demi sepotong seperti yang kita membaca darinya."

"Bagus sekali. Semuanya jelas. Apakah ada buffer untuk menulis?"

"Oh, tentu."

"Mungkin contohnya?"

"Bayangkan tempat sampah. Alih-alih pergi ke luar untuk membuang sampah ke insinerator setiap saat, Anda hanya membuangnya ke tempat sampah. Lalu Bubba membawa kaleng itu ke luar setiap dua minggu sekali. Penyangga klasik."

"Menarik sekali! Dan lebih jernih daripada sekantong gula, omong-omong."

"Dan metode flush() seperti membuang sampah dengan segera. Anda dapat menggunakannya sebelum tamu datang."