"สวัสดี อามีโก้"

“สวัสดีครับคุณริชชี่”

"วันนี้ฉันจะอธิบายหัวข้อใหม่และน่าสนใจให้คุณฟัง: พร็อกซีแบบไดนามิก" .

"Java มีหลายวิธีในการเปลี่ยนฟังก์ชันการทำงานของคลาสเฉพาะ..."

"วิธีแรกคือการสืบทอด"

"วิธีที่ง่ายที่สุดในการเปลี่ยนแปลงพฤติกรรมของคลาสคือการสร้างคลาสใหม่ที่สืบทอดคลาสดั้งเดิม (ฐาน) และแทนที่เมธอดของคลาสนั้น จากนั้น แทนที่จะใช้คลาสดั้งเดิม คุณใช้คลาสที่ได้รับมา ตัวอย่างเช่น:"

Reader reader = new UserCustomReader();

"วิธีที่สองคือการใช้คลาส wrapper"

" BufferedReaderเป็นตัวอย่างของคลาสประเภทนี้ ประการแรก มันสืบทอดReaderกล่าวอีกนัยหนึ่ง มันสามารถใช้แทน Reader ได้ อย่างที่สอง มันเปลี่ยนเส้นทางการเรียกทั้งหมดไปยังออบ เจกต์ Reader ดั้งเดิม ซึ่งต้องส่งผ่านไปยังตัวสร้างของออบเจ็กต์ BufferedReader . ตัวอย่างเช่น:"

Reader readerOriginal = new UserCustomReader();
Reader reader = new BufferedReader(readerOriginal);

"วิธีที่สามคือการสร้างพร็อกซีแบบไดนามิก (Proxy)"

"มีคลาสพิเศษใน Java (java.lang.reflect.Proxy) ที่ให้คุณสร้างออบเจกต์ระหว่างการทำงานของโปรแกรม (ไดนามิก) โดยไม่ต้องสร้างคลาสแยกต่างหากสำหรับคลาสนั้น"

"นี่เป็นเรื่องง่ายมากที่จะทำ:"

Reader reader = (Reader)Proxy.newProxyInstance();

"นั่นเป็นสิ่งใหม่สำหรับฉันแล้ว!"

"แต่แน่นอน เราไม่ต้องการออบเจ็กต์ที่ไม่มีเมธอด เราต้องการให้อ็อบเจกต์มีเมธอด และเราต้องการให้ออบเจ็กต์ทำในสิ่งที่เราต้องการ Java ใช้อินเทอร์เฟซพิเศษสำหรับ InvocationHandler ซึ่งสามารถสกัดกั้นการเรียกใช้เมธอดทั้งหมด เชื่อมโยงกับวัตถุพร็อกซี วัตถุพร็อกซีสามารถสร้างได้โดยใช้อินเทอร์เฟซเท่านั้น"

" เรียกใช้ – เป็นชื่อมาตรฐานสำหรับเมธอดหรือคลาสที่มีหน้าที่หลักในการเรียกใช้เมธอดบางอย่าง"

" Handler – เป็นชื่อมาตรฐานสำหรับคลาสที่จัดการเหตุการณ์บางอย่าง ตัวอย่างเช่น คลาสที่จัดการการคลิกเมาส์จะเรียกว่า MouseClickHandler เป็นต้น"

"อินเทอร์เฟซ InvocationHandler มีวิธีการเรียกใช้วิธีเดียว ซึ่งเรียกการเรียกทั้งหมดไปยังวัตถุพร็อกซีตัวอย่างเช่น:"

รหัส
Reader reader = (Reader)Proxy.newProxyInstance(new CustomInvocationHandler());
reader.close();
class CustomInvocationHandler implements InvocationHandler
{
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
 {
  System.out.println("yes!");
  return null;
 }
}

"เมื่อเรียกใช้ เมธอด reader .close () เมธอด invokeจะถูกเรียกใช้ และหน้าจอจะแสดง 'yes!' "

"ดังนั้นเราจึงประกาศCustomInvocationHandlerคลาส และนำ อินเทอร์เฟซ InvocationHandlerและ เมธอดการ เรียกใช้มาใช้ เมื่อเรียกใช้เมธอด จะแสดง 'ใช่!' จากนั้นเราสร้าง ออบเจกต์ CustomInvocationHandlerและส่งต่อไปยัง เมธอด newProxyInstanceเมื่อสร้าง วัตถุพร็อกซี"

"ใช่ ถูกต้องทั้งหมด"

"นี่เป็นเครื่องมือที่ทรงพลังมาก โดยปกติแล้ว พร็อกซีเหล่านี้ถูกสร้างขึ้นเพื่อจำลองวัตถุในโปรแกรมที่กำลังทำงานอยู่บนคอมพิวเตอร์เครื่องอื่น  หรือเพื่อควบคุมการเข้าถึง"

"คุณสามารถตรวจสอบสิทธิ์ของผู้ใช้ปัจจุบัน จัดการกับข้อผิดพลาด บันทึกข้อผิดพลาด และอื่นๆ อีกมากมายได้ด้วยวิธีการนี้"

"นี่คือตัวอย่างที่เมธอดเรียกใช้ยังเรียกเมธอดของออปเจกต์ดั้งเดิมด้วย:"

รหัส
Reader original = new UserCustomReader();

Reader reader = (Reader)Proxy.newProxyInstance(new CustomInvocationHandler(original));
reader.close();
class CustomInvocationHandler implements InvocationHandler
{
 private Reader readerOriginal;

 CustomInvocationHandler(Reader readerOriginal)
 {
  this.readerOriginal = readerOriginal;
 }

 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
 {
  if (method.getName().equals("close"))
  {
   System.out.println("Reader closed!");
  }

  // This calls the readerOriginal object's close method.
  // The method's name and a description of its parameters are stored in the method variable.
  return method.invoke(readerOriginal, args);
 }
}

"ตัวอย่างนี้มีคุณสมบัติพิเศษสองประการ"

"อย่างแรก ออบเจ็กต์ «ต้นฉบับ» Readerจะถูกส่งผ่านไปยังคอนสตรัคเตอร์ และการอ้างอิงไปยังอ็อบเจ็กต์นั้นจะถูกบันทึกไว้ในCustomInvocationHandler "

"อย่างที่สอง เราเรียกเมธอดเดิมนี้อีกครั้งใน invoke method แต่ครั้งนี้เรียกออปเจ็กต์ «ดั้งเดิม»"

"อ่า พูดอีกอย่างคือ บรรทัดสุดท้ายนี้เรียกเมธอดเดียวกัน แต่ใช้ออปเจ็กต์เดิม:"

return method.invoke(readerOriginal, args);

"ใช่."

"ฉันจะไม่บอกว่ามันชัดเจนมาก แต่ก็ยังเข้าใจได้ หรือดูเหมือนว่า"

"เยี่ยมมาก แล้วอีกอย่าง ในเมธอด newProxyInstance คุณต้องส่งข้อมูลการดูแลเพิ่มเติมอีกเล็กน้อยเพื่อสร้างวัตถุพร็อกซี แต่เนื่องจากเราไม่ได้สร้างวัตถุพร็อกซีขนาดมหึมา ข้อมูลนี้จึงได้รับอย่างง่ายดายจากคลาสเดิม "

"นี่เป็นอีกตัวอย่างหนึ่ง:"

รหัส
Reader original = new UserCustomReader();

ClassLoader classLoader = original.getClass().getClassLoader();
Class<?>[] interfaces = original.getClass().getInterfaces();
CustomInvocationHandler invocationHandler = new CustomInvocationHandler(original);

Reader reader = (Reader)Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
class CustomInvocationHandler implements InvocationHandler
{
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
 {
  return null;
 }
}

"อ่า ClassLoader และรายการอินเทอร์เฟซ นี่เป็นบางอย่างจาก Reflection ใช่ไหม"

"ใช่."

"ฉันเข้าใจแล้ว ฉันคิดว่าฉันสามารถสร้างวัตถุพร็อกซีแบบดั้งเดิมที่เรียบง่ายสุด ๆ ได้ ถ้าฉันต้องการ"

"จากนั้นไปตรวจสอบกับดิเอโก"