ตอน 6 : Polymorphism


ไปหน้าแรก      สารบัญ        Laploy.com    ระเบียนบทความ      บทความจากลาภลอย


เว็บไซต์นี้เป็นตัวอย่างเนื้อหาบางตอนในหนังสือ "เรียนรู้ด้วยตนเอง OOP C# ASP.NET" ครอบคลุม บทที่ 1 ถึงบทที่ 6 (ในหนังสือมี 21 บท) เนื้อหาใน Blog อาจอาจแตกต่างจากในหนังสือเพราะเป็นเนื้อหาที่ยังไม่ได้ตรวจแก้ขัดเกลา (edit)

กดที่นี่เพื่อดูรายละเอียดเนื้อหาในแต่ละบท

กดที่นี่เพื่อไปยังเว็บบอร์ด ถาม-ตอบ 

 

 

Polymorphism

 

คำจาร์กอนของ OOP ที่ผู้คนหวาดกลัวมากที่สุดคือคำว่า polymorphism เพราะมันชวนให้นึกถึงยัญพิธีอันลี้ลับที่ hacker ประกอบในที่รโหฐาน แต่ตรงกันข้าม อันที่จริง polymorphism เป็นสิ่งเรียบง่ายที่แม้เด็กเล็กๆ ก็เข้าใจทุกคน

ท่านเคยเห็นเด็กเล่นดินน้ำมันหรือไม่ เด็กชอบดินน้ำมันเพราะนอกจากจะมีสีสันสวยงามแล้ว ยังนำมาปั้นให้เป็นรูปทรงอะไรก็ได้ตามใจชอบ คำว่า polymorphism (อ่านว่าโพลีมอร์ฟิส) มาจากคำในภาษากรีกสองคำ คือ poly (โพลี) แปลว่า หลาย และ morphism (มอร์ฟิส) แปลว่า รูปร่าง polymorphism จึงแปลว่า “หลายรูปทรง” หรือ “แปลงสภาพได้” เช่นเดียวกับดินน้ำมันที่เด็กๆ นำมาปั้นเป็นรูปทรงต่างๆ ได้หลายแบบ

ท่านอาจสงสัยว่าอะไรที่เปลี่ยนรูปร่างได้ และการเปลี่ยนรูปร่างได้มีประโยชน์อย่างไร คำตอบคือสิ่งที่เปลี่ยนรูปร่างได้คือ method ที่สืบสันดานมาจาก base class ประโยชน์คือช่วยให้เรานำคลาสมาใช้ได้โดยสามารถเปลี่ยนแปลง method บาง method ของ base class ให้ตรงกับความต้องการ (เรียกว่า method override) หรือสร้าง method ใหม่ทับของเดิมไปเลย (เรียกว่า method hiding)

ท่านจะเข้าใจหลักการ polymorphism เมื่อท่านเข้าใจการทำ method hiding และ method override ดังนั้นต่อไปนี้ผู้เขียนจะอธิบายสองเรื่องนี้ด้วยการยกตัวอย่างและแสดงโค้ด

 

method overriding

ยกตัวอย่างประโยชน์ของการทำ method overriding เช่น ผู้เขียนได้รับคลาสชื่อ CustomerData มาจากนายสมชาย นักเขียนโค้ดที่เป็นเพื่อร่วมงาน เป็นคลาสทำหน้าที่จัดการกับฐานข้อมูลลูกค้า คลาสนี้มี method อยู่ภายในจำนวนมาก ผู้เขียนใช้งานคลาสนี้มาหลายเดือนโดยไม่มีปัญหา

อยู่มาวันหนึ่งบริษัทโทรศัพท์ทั่วประเทศเพิ่มหมายเลขโทรศัพท์เป็น 12 หลัก ผู้เขียนพบว่าคลาส CustomerData ไม่สามารถรองรับการทำงานได้ จำเป็นต้องแก้ไขส่วน method ชื่อ CustomerPhone() ซึ่งทำหน้าที่จัดการหมายเลขโทรศัพท์ แต่ปัญหาคือนายสมชายได้ลาออกไปแล้ว ผู้เขียนไม่สามารถแก้ไข method CustomerPhone() ได้เพราะไม่มี source code

โชคดีที่นายสมชายเขียนคลาส CustomerData ไว้เป็น OOP โดยสมบูรณ์ ผู้เขียนจึงสามารถสร้างคลาสใหม่โดยสืบสันดานจากคลาสนี้ แล้วทำ method override โดยเขียนเฉพาะ method CustomerPhone() ขึ้นใหม่ ให้รองรับหมายเลขโทรศัพท์ 12 หลัก เนื่องจากผู้เขียนไม่เปลี่ยนแปลงวิธีเรียกใช้ method CustomerPhone()ผู้เขียนจึงไม่ต้องแก้ไขโค้ดภายนอกที่เรียกใช้ method นี้

 

หนังสือชื่อ Programming Microsoft Visual C# 2005: The base class libray สอนเทคนิคการนิยาม base class และ interface

 

method hiding

ต่อไปจะยกตัวอย่างประโยชน์ของการทำ method hiding คลาส CustomerData นี้มี method ชื่อ CleanAll() ทำหน้าที่ลบข้อมูลจากฐานข้อมูลทั้งหมด ผู้เขียนจะต้องมอบคลาสนี้ให้นักเขียนโค้ดผู้เป็นลูกทีมไว้ใช้งาน แต่ผู้เขียนไม่ต้องการให้ลูกทีมลบข้อมูลออกจากฐานข้อมูล ผู้เขียนจึงสร้างคลาสใหม่โดยสืบสันดานจากคลาส CustomerData แล้วทำ method hiding โดยการเขียนเฉพาะ method CleanAll() ขึ้นใหม่แต่ไม่ใส่โค้ดใดๆ ไว้ใน method ดังนั้นแม้ผู้นำคลาสนี้ไปใช้จะมองเห็น และเรียกใช้ method CleanAll() ได้ตามเดิม แต่จะไม่สามารถลบข้อมูลออกจากฐานข้อมูลได้

 

ต่อไปนี้คือตัวอย่างโปรแกรมของคลาส CustomerData โดยเขียนให้สั้นที่สุดเพื่อให้เข้าใจง่าย

 

class CustomerData
{
     protected virtual void CustomerPhone()
     {
          Console.WriteLine("02 123 456");
     }
     protected virtual void ClearAll()
     {
          Console.WriteLine("delete all data");
     }
}

 

เนื่องจากเป็นโค้ดตัวอย่าง ภายในคลาสจึงมีสมาชิกเพียงสอง method (ในคลาสจริงจะมีสมาชิกจำนวนมาก) ในแต่ละ method ทำงานเพียงแค่แสดงข้อความ (ในคลาสจริงจะมีโค้ดดำเนินการต่างๆ แทน)

ขอให้สังเกตว่า method CustomerPhone() ได้ถูกกำหนด modifier (อ่านว่า โมดิไฟร์เออร์ แปลว่าตัวแก้ไข ตัวดัดแปลง ในภาษา C# มีจำนวนมาก เช่น abstract, const, event, extern โปรดอ่านรายละเอียดในบทที่ 4 หัวข้อ type modifier) ให้เป็น virtual แสดงให้เห็นเจตนาของผู้เขียนโค้ด ที่ต้องการให้ผู้อื่นนำคลาสนี้ไปสืบสันดานเป็นคลาสใหม่ (คือนำไปใช้เป็น base class) และสามารถทำ override method นี้ได้ โปรดจำไว้ว่าในภาษา C# virtual และ override จะใช้คู่กัน

ต่อไปนี้เป็นตัวอย่างการสร้างคลาสใหม่โดยสืบสันดานจากคลาส คลาส CustomerData

 

1 class CustomerData2 : CustomerData
2 {
3      protected override void CustomerPhone()
4      {
5           base.CustomerPhone();
6           Console.WriteLine("02 123 456 7");
7      }
8      protected new virtual void ClearAll()
9      {
10     }
11 }

 

คลาสใหม่นี้ชื่อ CustomerData2 ผู้เขียนใช้สาทิตการทำ override และ hiding ไปพร้อมๆ กันในคลาสเดียว บรรทัดที่ 3 ถึง 7 คือตัวอย่างการทำ method override ซึ่งเป็นการเขียน method ใหม่ให้ทำงานแทน method ที่มี signature เดียวกันที่อยู่ใน base class (signature เหมือกันหมายถึงมี return type, method name และ parameter list ตรงกัน โปรดอ่านรายละเอียดเรื่อง method signature ในบทที่ 4)

ท่านคงสังเกตว่าในทั้งในคลาส CustomerData และคลาส CustomerData ต่างมี method ชื่อ CustomerPhone() ด้วยกันทั้งคู่ เนื่องจากคลาส CustomerData2 สืบสันดานจากคลาส CustomerData มันจึงรับมรดกสมาชิกทั้งหมดของคลาส CustomerData มาอยู่แล้ว การนิยาม method CustomerPhone()ในคลาส CustomerData2 ซ้ำอีกจึงเท่ากับทับการทำงานของ method CustomerPhone() ในคลาส CustomerData

คำสั่งบรรทัดที่ 5 เป็นเทคนิคที่น่าสนใจ นี่คือวิธีเรียกใช้ method CustomerData ตัวที่อยู่ใน base class ดังนั้นเมื่อ method CustomerData ของคลาส CustomerData2 ทำงาน method CustomerData ตัวที่อยู่ใน base class ก็จะทำงานด้วย เทคนิคนี้มีประโยชน์กรณีที่เราต้องการ override เพื่อเพิ่มเติมการทำงานของ method ใน base class

 

protected modifier

โปรดสังเกตว่า method CustomerPhone()ของคลาส CustomerData มี access modifier เป็น protected และมี type modifier เป็น virtual และ method CustomerPhone()ของคลาส CustomerData2 มี access modifier เป็น protected เช่นกันแต่มี type modifier เป็น override อันเป็นการใช้คู่กันอย่างที่เรียนให้ทราบไปแล้ว

การกำหนด access modifier ให้ method เป็น protected เป็นการแสดงเจตนาของผู้เขียนว่าต้องการให้ผู้นำคลาสนี้ไปใช้เป็น base class เพราะ method ที่เป็น protected จะถูกเข้าถึงได้จาก derived class เท่านั้น หากนำคลาสนี้ไปสร้าง object โค้ดภายนอกจะเรียกใช้ method นั้นไม่ได้

หากท่านไม่กำหนด method ของ base class ให้เป็น virtual แล้วพยายามทำ method override (ในคลาส CustomerData2) โปรแกรมจะคอมไพล์ไม่ผ่าน และคอมไพเลอร์จะแจ้ง error 0506 ซึ่งมีข้อความบอกว่า method นั้นๆ override ไม่ได้ สิ่งนี้ทำให้ภาษา C# แตกต่างจากภาษ Java เพระภาษา Java หากไม่ถูกกำหนด method สมาชิกจะเป็น virtual ไปโดยปริยาย แต่ภาษา C# จะเป็น non-virtual (คือไม่ใช่ virtual)

คำสั่งบรรทัด 8 ถึง 10 แสดงตัวอย่างการทำ method hiding โดยนิยามคลาส ClearAll() ขึ้นใหม่และใช้ modifier new เพื่อทับการทำงานของ method เดียวกันใน base class ด้วยการไม่ใส่คำสั่งใดๆ ในบล็อกของ method ทำให้แม้จะเรียกใช้ method ได้แต่ก็จะไม่มีการทำงานเกิดขึ้น

 

shadowing

การทำ hiding นอกจากจะทำกับ method แล้ว ยังสามารถทำกับสมาชิกอื่นๆ ของคลาส (เช่น field, property, event และ indexer เป็นต้น) ได้ด้วย ในภาษาอื่นๆ ของ .NET มีการทำ hiding ทั้งนั้นแต่อาจเรียกเป็นอย่างอื่น เช่นภาษา VB.NET เรียกว่า shadowing เป็นต้น

จะเห็นว่า hiding มีประโยชน์เมื่อเราต้องการปิดบัง หรือเพิกถอนการทำงานของสมาชิกบางตัวใน base class ทั้ง hiding และ overriding เป็นกลไกสำคัญที่ทำให้ภาษา C# มีความสามารถด้าน polymorphism ในบทหลังๆ ของหนังสือเล่มนี้ท่านจะได้เรียนวิธีประยุกต์หลักการ polymorphism กับการเขียนโปรแกรมสร้างเว็บไซต์โดยละเอียด

ที่ท่านได้อ่านมาทั้งหมดเป็นสามเสาหลักสำคัญของ OOP นั่นคือ encapsulation, inheritance และ polymorphism หากท่านเข้าใจสามเรื่องนี้ ก็ถือว่าท่านเข้าใจหลักการ OOP ทั้งหมด หากท่านอ่านทฤษฏีในบทนี้แล้วยังไม่เข้าใจ และยังไม่สามารถคิดเป็น OOP ก็ไม่ต้องเป็นกังวล เพราะเมื่อท่านอ่านอย่างถี่ถ้วนและทำแบบฝึกหัดในบทต่างๆ ของหนังสือเล่มนี้ครบหมด ท่านก็จะเข้าใจและสามารถคิดแบบ OOP ได้ในที่สุด

 

ตอนต่อไป: OOP กับ Microsoft .NET Framework

Post a comment or leave a trackback: Trackback URL.

ใส่ความเห็น

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / เปลี่ยนแปลง )

Twitter picture

You are commenting using your Twitter account. Log Out / เปลี่ยนแปลง )

Facebook photo

You are commenting using your Facebook account. Log Out / เปลี่ยนแปลง )

Google+ photo

You are commenting using your Google+ account. Log Out / เปลี่ยนแปลง )

Connecting to %s

%d bloggers like this: