"สวัสดี Amigo! วันนี้ฉันจะบอกคุณถึงสิ่งที่น่าสนใจบางอย่างเกี่ยวกับคลาส BufferedInputStream แต่ขอเริ่มด้วย « กระดาษห่อ » และ « ถุงน้ำตาล »"

"คำว่า "กระดาษห่อ" และ "ถุงน้ำตาล" หมายความว่าอย่างไร"

"นี่เป็นอุปมาอุปไมย ฟังนะ ดังนั้น..."

รูปแบบการออกแบบ «wrapper» (หรือ «มัณฑนากร») เป็นกลไกที่ค่อนข้างง่ายและสะดวกสำหรับการขยายการทำงานของวัตถุโดยไม่ต้องใช้การสืบทอด

BufferedInputStream - 1

สมมติว่าเรามีคลาส Cat มีสองวิธี: getName และ setName:

รหัสจาวา คำอธิบาย
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());
}
ตัวอย่างของวิธีการใช้

«ออสการ์» จะแสดงบนคอนโซล

สมมติว่าเราจำเป็นต้องสกัดกั้นการเรียกใช้เมธอดบน วัตถุ catและอาจทำการเปลี่ยนแปลงเล็กน้อย สำหรับสิ่งนี้ เราจำเป็นต้องห่อมันในคลาสของกระดาษห่อของมันเอง

ถ้าเราต้องการ"ล้อม"โค้ดของเราเองไว้รอบเมธอดที่เรียกใช้ออบเจกต์บางอย่าง เราจำเป็นต้อง:

1)สร้างคลาส wrapper ของเราเองและสืบทอดจากคลาส / อินเตอร์เฟสเดียวกันกับวัตถุที่จะห่อ

2)ส่งวัตถุที่จะห่อไปยังตัวสร้างคลาสของเรา

3)ลบล้างเมธอดทั้งหมดในคลาสใหม่ของเรา เรียกใช้เมธอดของออบเจกต์ที่ห่อไว้ในแต่ละเมธอดที่ถูกแทนที่

4)ทำการเปลี่ยนแปลงตามที่คุณต้องการ: เปลี่ยนสิ่งที่เรียกใช้เมธอด เปลี่ยนพารามิเตอร์ และ/หรือทำอย่างอื่น

ในตัวอย่างด้านล่าง เราสกัดกั้นการเรียกเมธอด getName ของวัตถุ Cat และเปลี่ยนค่าส่งคืนเล็กน้อย

รหัสจาวา คำอธิบาย
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());
}
ตัวอย่างของวิธีการใช้

«แมวชื่อออสการ์».
จะแสดงบนคอนโซล

กล่าวอีกนัยหนึ่ง เราแทนที่วัตถุดั้งเดิมแต่ละชิ้นอย่างเงียบ ๆ ด้วยวัตถุห่อหุ้ม ซึ่งได้รับลิงก์ไปยังวัตถุดั้งเดิม การเรียกใช้เมธอดทั้งหมดบน wrapper จะถูกส่งต่อไปยังออบเจกต์ดั้งเดิมและทุกอย่างจะทำงานเหมือนเครื่องจักร

"ฉันชอบ วิธีแก้ปัญหานั้นง่ายและใช้งานได้จริง"

"ฉันจะบอกคุณเกี่ยวกับ «ถุงน้ำตาล» ด้วย นี่เป็นคำเปรียบเทียบมากกว่ารูปแบบการออกแบบ คำอุปมาของคำว่า buffer และ buffering อะไรคือ buffering และทำไมเราถึงต้องการมัน"

BufferedInputStream - 2

สมมติว่าวันนี้ถึงตาของฤๅษีทำอาหารและคุณช่วยเขา ฤๅษียังไม่มา แต่ข้าอยากดื่มชา ฉันขอให้คุณนำน้ำตาลหนึ่งช้อนเต็มมาให้ฉัน คุณไปที่ชั้นใต้ดินและหาถุงน้ำตาล คุณสามารถนำกระเป๋าทั้งใบมาให้ฉัน แต่ฉันไม่ต้องการถุงนั้น ฉันต้องการเพียงหนึ่งช้อนเต็ม แล้วเหมือนหุ่นที่ดี คุณเอาหนึ่งช้อนเต็มแล้วเอามาให้ฉัน ฉันเพิ่มมันลงในชา ​​แต่ก็ยังหวานไม่พอ และฉันขอให้คุณนำมาให้ฉันอีกครั้ง คุณไปที่ห้องใต้ดินอีกครั้งและนำอีกช้อนเต็ม จากนั้น Ellie ก็เข้ามา และฉันขอให้คุณนำน้ำตาลมาให้เธอ... ทั้งหมดนี้ใช้เวลานานเกินไปและไม่มีประสิทธิภาพ

ฤๅษีมาเห็นเข้าจึงขอให้นำขันน้ำตาลเต็มขันมาให้เขา จากนั้นฉันกับเอลลี่ก็เริ่มขอน้ำตาลกับริชิ เขาเพียงแค่เสิร์ฟให้เราจากชามน้ำตาลเท่านั้น และนั่นคือทั้งหมด

สิ่งที่เกิดขึ้นหลังจากฤๅษีปรากฏตัวเรียกว่าบัฟเฟอร์ : ชามน้ำตาลเป็นบัฟเฟอร์ ด้วยการบัฟเฟอร์ "ไคลเอนต์" สามารถอ่านข้อมูลจากบัฟเฟอร์เป็นส่วนเล็กๆในขณะที่บัฟเฟอร์เพื่อประหยัดเวลาและความพยายาม อ่านข้อมูลจากแหล่งที่มาเป็นส่วนใหญ่

"นั่นเป็นตัวอย่างที่ดี คิม ฉันเข้าใจดี การขอน้ำตาลหนึ่งช้อนเต็มก็เหมือนการอ่านหนึ่งไบต์จากลำธาร"

"ถูกต้อง คลาสBufferedInputStreamเป็นตัวอย่างคลาสสิกของ wrapper ที่มีบัฟเฟอร์ มันล้อมคลาส InputStream โดยจะอ่านข้อมูลจาก InputStream ดั้งเดิมในบล็อกขนาดใหญ่ลงในบัฟเฟอร์ แล้วดึงออกจากบัฟเฟอร์ทีละชิ้นในขณะที่เรา อ่านจากมัน”

"ดีมาก ทุกอย่างชัดเจน มีบัฟเฟอร์สำหรับเขียนหรือไม่"

"อ๋อ แน่นอน"

“ยกตัวอย่างได้ไหม”

"ลองนึกภาพถังขยะ แทนที่จะออกไปข้างนอกเพื่อใส่ขยะในเตาเผาทุกครั้ง คุณก็แค่โยนมันลงถังขยะ จากนั้น Bubba จะนำกระป๋องออกไปข้างนอกทุกสองสัปดาห์ บัฟเฟอร์แบบคลาสสิก"

"น่าสนใจจัง! แถมยังใสยิ่งกว่าน้ำตาลหนึ่งถุงเสียอีก"

"และวิธีการ flush() ก็เหมือนกับการกำจัดขยะทันที คุณสามารถใช้ก่อนที่แขกจะมาถึง"