การเข้าใจ Double Dispatch
ใน C#
เมื่อทำงานกับภาษาการเขียนโปรแกรมเชิงวัตถุอย่าง C# คุณอาจพบกับรูปแบบการออกแบบและเทคนิคต่างๆ ที่มุ่งแก้ปัญหาการเขียนโปรแกรมเฉพาะ รูปแบบหนึ่งของเทคนิคคือ double dispatch
ซึ่งในตอนแรกอาจดูสับสน ในบล็อกโพสต์นี้ เราจะเผยให้เห็นแนวความคิดเกี่ยวกับ double dispatch, พูดคุยว่าเมื่อไรควรใช้มัน, และให้ตัวอย่างโค้ดที่เป็นรูปธรรมเพื่อแสดงการใช้งานของมัน
Double Dispatch คืออะไร?
กล่าวให้ง่ายๆ ก็คือ double dispatch เป็นเทคนิคการเขียนโปรแกรมที่อนุญาตให้เลือกวิธีการ (method) ไม่เพียงแต่ขึ้นอยู่กับประเภทของวัตถุที่มันสังกัดอยู่ แต่ยังขึ้นอยู่กับประเภทของอาร์กิวเมนต์ (argument) อื่นที่ถูกส่งไปด้วย นี่หมายความว่าการตัดสินใจเกี่ยวกับว่าควรเรียกใช้วิธีการใดเกิดขึ้นในระหว่างการทำงาน (runtime) ไม่ใช่ในระหว่างการคอมไพล์ (compile time)
Single vs. Double Dispatch
-
Single Dispatch: จะเกิดขึ้นเมื่อคุณเรียกใช้วิธีการแบบเสมือน (virtual method) บนวัตถุ วิธีการที่ถูกเรียกใช้จะถูกกำหนดโดยขึ้นอยู่กับประเภทของวัตนั้น โดยเฉพาะ กล่าวคือ การ dispatch ขึ้นอยู่กับ “dispatcher” เพียงตัวเดียว: วัตถุหลัก
-
Double Dispatch: ซึ่งยกระดับขึ้นอีกขั้น ทั้งประเภทของวัตถุและประเภทของอาร์กิวเมนต์ของวิธีการจะถูกประเมินเพื่อกำหนดว่าควรดำเนินการวิธีการใด ซึ่งเป็นการแยกความแตกต่างที่สำคัญเพราะมันเปิดโอกาสให้ความยืดหยุ่นมากขึ้นในการดำเนินการวิธีการตามประเภทในระหว่างการทำงาน
การอธิบาย Multiple Dispatch
Double dispatch เป็นกรณีพิเศษของ multiple dispatch ใน multiple dispatch วิธีการสามารถรับอาร์กิวเมนต์ได้หลายอัน และทางเลือกของการดำเนินการที่ควรใช้งานขึ้นอยู่กับประเภทของอาร์กิวเมนต์แต่ละอัน ภาษาการเขียนโปรแกรมที่แตกต่างกันมีวิธีการจัดการกับ multiple dispatch ที่แตกต่างกัน โดยทั่วไปจะใช้ generic functions ที่สามารถปรับเข้ากับประเภทของอาร์กิวเมนต์ได้
เมื่อใดที่ควรใช้ Double Dispatch?
คุณอาจถามว่า: “เมื่อไรควรพิจารณาใช้ double dispatch?” นี่คือบางสถานการณ์:
- การโต้ตอบของวัตถุที่ซับซ้อน: เมื่อโปรแกรมของคุณต้องการให้วัตถุโต้ตอบในหลายวิธีตามประเภทเฉพาะของพวกเขา double dispatch ช่วยให้ความยืดหยุ่นนั้น
- ความสามารถในการใช้ Visitor Pattern: Visitor pattern ซึ่งเป็นกรณีการใช้งานที่มีชื่อเสียงของ double dispatch อนุญาตให้คุณกำหนดคำสั่งใหม่ในโครงสร้างโดยไม่ต้องเปลี่ยนประเภทของโครงสร้างนั้น
- การแก้ไขวิธีการแบบไดนามิก: หากคุณต้องการแก้ไขวิธีการตามประเภทในระหว่างการทำงานไม่ใช่ประเภทในระหว่างการคอมไพล์ double dispatch สามารถให้ความสามารถที่จำเป็นได้
การนำ Double Dispatch ไปใช้ใน C#
ตอนนี้เรามาเข้าใจแนวคิดกันแล้ว มาสำรวจวิธีการนำ double dispatch ไปใช้ใน C# ซึ่งด้านล่างนี้เป็นตัวอย่างโค้ดเพื่อแสดงเทคนิคนี้
ตัวอย่างโค้ด
using System.Linq;
class DoubleDispatch
{
public T Foo<T>(object arg)
{
var method = from m in GetType().GetMethods()
where m.Name == "Foo"
&& m.GetParameters().Length==1
&& arg.GetType().IsAssignableFrom(m.GetParameters()[0].GetType())
&& m.ReturnType == typeof(T)
select m;
return (T) method.Single().Invoke(this, new object[]{arg});
}
public int Foo(int arg) { /* Implementation here */ }
static void Test()
{
object x = 5;
Foo<int>(x); // Calls Foo(int) via Foo<T>(object).
}
}
การวิเคราะห์โค้ด
- การกำหนดวิธีการแบบเจนเนอริก: วิธีการ
Foo<T>
ถูกประกาศให้เป็นเจนเนอริกเพื่อให้สามารถอนุญาตให้การอนุมานประเภท - การเลือกวิธีการ: วิธีการเลือกวิธีการ
Foo
ที่เหมาะสมโดยการตรวจสอบประเภทอาร์กิวเมนต์ในระหว่างการทำงาน - การเรียกใช้วิธีการ: สุดท้าย วิธีการที่เลือกจะถูกเรียกใช้ด้วยอาร์กิวเมนต์
สรุป
Double dispatch เป็นเทคนิคที่มีพลังที่ช่วยให้การดำเนินการวิธีการแบบไดนามิกมากขึ้นตามประเภทในระหว่างการทำงานใน C# ไม่ว่าคุณจะกำลังดำเนินการตาม visitor pattern หรือเพียงแค่ต้องการการแก้ไขวิธีการที่ยืดหยุ่น double dispatch เป็นเครื่องมือที่ล้ำค่าในชุดเครื่องมือของนักพัฒนา C# โดยการทำความเข้าใจว่ามันทำงานอย่างไรและวิธีการนำไปใช้ คุณสามารถสร้างแอปพลิเคชันที่ซับซ้อนและปรับตัวได้มากขึ้น
โดยการรวม double dispatch
เข้ากับแนวทางปฏิบัติในการเขียนโปรแกรมของคุณ คุณสามารถปรับปรุงการออกแบบและฟังก์ชันการทำงานของแอปพลิเคชัน C# ของคุณ ขอให้สนุกกับการเขียนโค้ด!