Refactoring to better use of polymorphism

What is polymorphism?

นึกย้อนกลับไปเมื่อประมาณวันอังคารที่แล้ว ในการสอบสัมภาษณ์ committee ถามว่า “polymophism คืออะไร?” กับเด็กจบใหม่ที่มาสมัครงานคนหนึ่ง (คำถามคลาสสิค) – คำตอบที่ได้กลับมาคือ

“มันคือ method overloading ครับ/ค่ะ”

ใช่ครับ อาจารย์พี่ก็สอนมาแบบนี้…

ผมว่าคำถามนี้มันกึ่งๆ open-ended question คือคำตอบมันขึ้นกับความเข้าใจที่มีใน OO บวกประสบการณ์การเขียนจริง – มันคงไม่ถึงกับผิด ถ้าคุณ ไม่ตอบออกทะเล ที่สำคัญคือคุณตอบ “ครบ” แค่ไหน?

Polymorphism is all around

Method Overloading เป็นส่วนหนึ่งของคอนเซ็ปต์ polymorphism แต่มันไม่ใช่ทั้งหมดของ polymorphism อันนี้ต้องพูดให้เคลียร์นิดนึง – ตามความเข้าใจของผม Polymorphism มีหลายประเภทด้วยกัน

  • ad-hoc polymorphism: คือการใช้ inheritance + method overloading + dynamic binding โดยให้ compiler/interpreter เป็นผู้เลือกว่าจะ เรียกการกระทำจาก object ไหนตอนรันไทมน์
  • parametic polymorphism: คือการกำหนดประเภทของ object ที่รับ/ส่งเมสเสจแบบ “กว้างๆ” เพื่อให้สามารถใช้ได้กับทุกคลาส (หรือบางคลาส เมื่อมี constraint) ยกตัวอย่างเช่น generic collection – List<T>

พูดง่ายๆคือการรับ/ส่งเมสเสจแบบ “กว้างๆ” ไม่เจาะจงว่าผู้รับ/ส่งจะเป็นใครในขณะที่เขียนโค้ด เดี๋ยวมันก็รู้เองตอนรันนั่นแหละ

So what?

แล้วมันช่วยห่า(น) อะไรกับชีวิตโปรแกรมเมอร์ตาดำๆครับ?

ลองมาดูโค้ดกัน

Rev.1

public void DoSthWithAnimal(Animal animal) {
if(animal is Duck) {
// Do something with a duck
...
} else if(animal is Rat) {
// Do something with a rat
...
} else if(animal is Cat) {
// Do something with a cat
...
}
...
}

ข้อสังเกต:

  • Code Readability ต่ำ ลองนึกภาพข้างในแต่ละ if statement มีโค้ดสักร้อยบรรทัด
  • จะเปลี่ยนจาก if…else เป็น switch statement ก็ไม่ต่างกันเท่าไหร่
  • เมื่อมี conditional statements จากการเช็ค flag อะไรบางอย่าง ความน่าจะเป็นที่จะมีการเช็คแบบเดียวกันซ้ำๆ ในตำแหน่งที่ต่างกันนั้นมีสูง (ต้องเขียนซ้ำๆ copy-paste นั่นแหละ)

Rev. 2

public void DoSthWithAnimal(Animal animal) {
// Do something with a duck, rat, cat or other defined types in the future
animal.Action();
...
}

ข้อสังเกต:

  • โค้ดสะอาดขึ้น เพราะย้ายการกระทำที่เป็น common ไปไว้เมทอด Action – หากมีการกระทำไหนที่ Duck, Rat, Cat ต้องการเป็นพิเศษก็ใช้ overloading นิยามเพิ่มเข้าไป
  • ทุกจุดที่เคยเช็ค condition ซ้ำๆก็จะหายไป (เลิกนิสัย copy-paste)
  • สิ่งสำคัญคือ Maintainability ที่เพิ่มขึ้น เมื่อเกิดความต้องการเช็คประเภทใหม่ในระบบ ไม่จำเป็นต้องเปลี่ยน client code สิ่งที่ต้องทำคือ derive คลาส Animal และ overload method Action ถ้าจำเป็น

Why asking OOP concept during interview?

หลายคนอาจสงสัยว่าทำไมตอนสอบสัมภาษณ์งาน มักเจอคำถามคอนเซ็ปต์ของ OOP? ตอนแรกผมก็ไม่เข้าใจว่าทำไมถึงให้ความสำคัญกับทฤษฎี ในเมื่อเขียนโค้ดได้ก็น่าจะพอ – แต่พอทำงานไปสักสาม-สี่ปีก็ถึงบางอ้อ

เพราะ scale ของงานมันต่างกับตอนเรียน โปรเจ็กต์ขนาดกลางถึงใหญ่ที่มีโค้ดหลายพัน-หมื่นบรรทัดนั้น การเขียนให้ maintainable ไม่ใช่เรื่องง่ายเลยจริงๆ

หากว่าสักแต่เขียน เมื่อมี requirement ใหม่เข้ามา อาจถึงกับต้องทำการ “รื้อ” เลยทีเดียว – บ่อยครั้งที่การเพิ่มฟีเจอร์ง่ายๆกลับกลายเป็นเรื่องยาก เพราะคนเขียนไม่ให้ความสำคัญกับทฤษฎีตั้งแต่แรก

ส่งท้ายด้วย quote ของเจ้าพ่อ Martin Fowler:

Any fool can write code that a computer can understand. Good programmers write code that humans can understand. – Martin Fowler

Summary

  • ตัวอย่างที่กล่าวมาข้างต้นเป็นวิธีใช้ polymophism อย่างหนึ่งของการ refactoring ดูรายละเอียดได้ที่ refactoring.com หรือหนังสือของ Martin Fowler
  • ที่จริงยังมีนิยามประเภทของ polymorphism อีกสองอย่างคือ coercion และ inclusion แต่ไม่พูดถึงในที่นี้ ดูรายละเอียดได้ที่ Java World
  • บทความนี้เขียนตามความเข้าใจของผู้เขียน หากผิดพลาดประการใดหรือมีข้อเสนอแนะ ยินดีรับคอมเม้นต์ด้านล่าง

References

4 Comments

  1. SY
    Posted March 15, 2009 at 11:23 pm | #

    ท่าทางจะโมโห
    อย่ากระโดดกััดคอเด็กล่ะ :D

  2. Hana
    Posted March 16, 2009 at 3:50 pm | #

    มิน่าล่ะ โดนเคี่ยวเข็ญเรื่อง OOP ทู้กที

  3. Orbit
    Posted March 16, 2009 at 10:55 pm | #

    ประสบการณ์ตรงเลยนะเนี่ย

  4. baLLe
    Posted March 18, 2009 at 12:36 pm | #

    คำเค้าคมจริงๆ

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>