Implementation Inheritance #5 : The Devil

    มาถึงจนได้บทสุดท้ายของ Implementation Inheritance แต่ใช่ว่าเนื้อหาจะมีเพียงเท่านี้นะครับ เอาเข้าจริงๆ ยังมีอีกมาก สำหรับผมคงหยุดตรงนี้ ถ้ามีโอกาสดีๆ มีคนเรียกร้องมา ก็อาจจะเขียนเพิ่ม

    ในบทก่อนๆ เราผ่านเนื้อหา พอเห็น Implementation Inheritance กันลางๆ แล้ว มาวันนี้ซึ่งเป็นบทสุดท้ายของเรื่องนี้ ผมจะคุยเรื่องข้อจำกัดของมันบ้าง เพื่อจะได้เห็นรอบด้าน

    ผมเริ่มที่ Microsoft ก่อนดีกว่า ว่าเขามีความเห็นอย่างไรกับเรื่องนี้ ทาง Microsoft มีความเห็นอย่างรุนแรงมากต่อ Implementation Inheritance ว่ามันเป็นสิ่งที่แย่มากๆ เขาอ้างว่าเราไม่มีทางเขียนโปรแกรมขนาดใหญ่ได้โดยใช้ Implementation Inheritance เขียนโจมตีใน Web เฉยๆ คงไม่เป็นไร แต่ Microsoft กลับทำรุนแรงกว่านั้น คือในปี 1999 ให้อาจารย์มหาวิทยาลัยหลายคน ที่ Microsoft สนับสนุนเรื่องเงินทุนอยู่ ออกไปตระเวณทั่วโลก ตามมหาวิทยาลัยและงานสัมมนาต่างๆ ไปให้ความรู้ที่สาธารณะว่า Implementation Inheritance มันไม่ดีอย่างมาก อย่าได้เอาไปใช้เลย อะไรทำนองนั้น ถ้าจะใช้ ให้ใช้ Interface-Based  Inheritance แทนจะดีกว่ามาก เมื่อ Microsoft เล่นกลยุทธ์นี้ ในวงการการศึกษาซึ่งมีการทะเลาะกันเรื่อง Implementation Inheritance ว่าเป็นนักบุญหรือปีศาจอยู่แล้ว ก็ยิ่งทวีความรุนแรงมากขึ้นอีก คุณเชื่อรึเปล่าว่าจนบัดนี้ยังทะเลาะกันไม่จบ มันคงเหมือนเรื่องศาสนา อย่าได้เริ่มจะดีกว่า

    ผมมาคิดเอาเองนะ ว่า Microsoft เองไม่ค่อยได้เน้นวิชาการอยู่แล้ว มีอะไรเป็นที่นิยมหน่อยก็จะลอก แต่ครั้งนี้มาแปลก มาคุยทางทฤษฏี แล้วผมก็ถึงบางอ้อ ตรงที่ว่าขุนพลหลักของ Microsoft คือ Visual Basic สันหลังหวะ ไม่รองรับ Implementation Inheritance รับได้แต่ Interface Inheritance มิน่าหละ! อันนี้เป็นความคิดของผมเองนะ ไม่ได้ไปได้ข้อมูลจากที่ไหน และแล้วมาวันนี้ Microsoft ก็กลืนน้ำลายตัวเองอีกครั้ง (ไม่รู้เป็นครั้งที่เท่าไหร่แล้ว) ใน VB.Net รุ่นใหม่นี้ รองรับ Implementation Inheritance ครับ

    หลังจากได้แซว Microsoft แล้ว รู้สึกดีขึ้น เรามาต่อเรื่องของเราดีกว่า  คนส่วนมากที่เริ่มเรียน OOP สิ่งที่เขาคิดว่าสุดยอดก็มักจะหนีไม่พ้นเรื่อง Implementation Inheritance เขามักจะคิดว่ามันเป็นเหมือนไม้เท้าวิเศษที่จะเนรมิตอะไรก็ได้  ถ้าคุณอ่านบทที่แล้วของผมที่ว่าด้วยเรื่อง .Net Example คุณคงรู้สึกเช่นนั้น แต่... ในความเป็นจริง ไม่ใช่ว่าคุณสามารถทำอย่างนั้นได้เสมอไป เพราะอะไร เรามาดูกัน

ถ้าคุณสร้าง Base Class ไม่ดี ปิดเกินไป มันก็ทำ Inherit ไปยัง Derive Class ไม่ได้

    ถ้าคุณสร้าง Base Class ไม่ดี ทุกอย่างซ่อน เป็น private หมด พอคุณมาทำ Inherit ไปยัง Dervice Class มันก็จะทำต่อไม่ได้ เพราะตัวแปร/ function เหล่านั้นถูก encapsulation หมด เป็น Black Box เลยจริงๆ เช่นตัวอย่าง class Robot ที่ผมยกตัวอย่างให้เห็นในบทก่อนๆ จะเห็นได้ว่า job1 ถึง job4 ถูกซ่อนหมด เลยเรียกใช้ไม่ได้

อะไรจะเกิดขึ้นถ้าเปิดหมด?

    ถ้าคุณทำอย่างนั้นคุณจะเสีย Encapsulation ทันที คือทุกตัวคุณเปิดเป็น public หมด หรือให้ดีหน่อยก็เป็น protected หมด การเป็น public หรือ protected นั้นเรา ถ้าเป็นตัวแปรจะเกิดปัญหาหนักหน่อยเพราะ ถ้ามาใส่ค่าที่ผิดเข้ามา ก็จะหาต้นตอได้ลำบาก  และยิ่งไปกว่านั้นดูในหัวข้อถัดไปข้างล่างนี้ครับ 

เมื่อมี Derived Class จะทำให้ Base Class แก้ได้ยาก

     เรื่องนี้เห็นจะเข้าใจไม่ยาก เมื่อเราสร้าง Derived Class ขึ้นมา มันจะต้องโอนเอา Interface ทั้งหมดของ Base Class ไป ดังนั้น Base class จะเสียอิสระในการเปลี่ยนแปลง Interface เพราะถ้าเปลี่ยนมันอาจจะส่งผลทำให้ Derive Class ทำงานไม่ได้ ดังนั้นเวลาออก class ใดๆ ก็ตามต้องออกแบบเผื่อว่าจะมีใคร Inherit ไปด้วย คุณไม่อาจทำแบบชุ่ยๆ ไปก่อน ด้วยเหตุผลข้างต้น ดังนั้น class จึงไม่ใช่สิ่งวิเศษที่จะไปปรับปรุงอะไรเมื่อไหร่ก็ได้ตามใจชอบ แต่หากต้องมองเผื่อถึงอนาคตว่าจะมีใคร inherit มันบ้าง ซึ่งในชีวิตจริง เราอาจจะไม่สามารถเผื่ออะไรได้ขนาดนั้น หรือทำได้แต่ก็ต้องใช้สมองคิดหนัก ที่เราให้ Library ของภาษาต่างๆ inherit กันเป็นลำดับชั้นซับซ้อน ดูเสมือนว่า inheritance ช่างดูดีขนาดนั้น จริงๆ แล้วมันไม่ใช่ครับ ที่เราเห็นว่ามันเป็นลำดับชั้นซับซ้อนนั้น มันเป็นการออกแบบรวบกันเป็นครั้งเดียว ไม่ใช่ปรับปรุงมาหลายรุ่น คงเข้าใจนะครับ

    ถ้าคุณต้องการความปลอดภัยจริงๆ ให้ยึดหลักว่า ถ้าคุณ แจกจ่าย object ของ คุณไปให้คนอื่นแล้ว หรือมีโปรแกรมใดโปรแกรมหนึ่งเรียกใช้มันแล้ว ห้ามแก้ interface ครับ เพิ่มได้ แต่อย่าแก้หรือลบ มันจะได้ไม่กระเทือน Derived Classes แต่ในความเป็นจริงมันเป็นไปได้หรือ?

เปิดก็ไม่ได้ ปิดก็ไม่ดี แล้วจะเอายังไง

       เป็นกฏเหมือนเดิมครับ ตัวแปรต้อง private อย่างเดียวห้าม protected ถ้ายังไงก็ทำเป็น property แบบ protected ก็ยังดี  การทำอย่างนี้เพื่อรักษา Encapsulation เอาไว้ และยังคงความเป็น black-box re-use คือ re-use code โดยไม่ต้องรู้โครงสร้างภายในของมัน ไม่กลายเป็น white-box re-use ซึ่งหมายถึง derive class ต้องรู้รายละเอียดของ base class แต่นั่นมันก็เป็นศิลปะ คุณต้องมีประสบการณ์อย่างน้อยซักครึ่งปีลองผิดลองถูก จนกระทั่งคุณเข้าใจว่าเมื่อใหร่ควรใช้ public/private หรือ protected มันมีจุดสมดุลอยู่ มันขึ้นอยู่กับ style การเขียนโปรแกรมของคุณเองด้วย

ทำอย่างไรถึงเป็น Black-box Reuse?

    การทำให้เป็น Black-box Reuse นั้น คือการที่ไม่ให้ใครล่วงรู้สิ่งต่างๆ ใน class ที่ตั้งใจซ่อนไว้ ผู้ที่เอา class ไป derive ต่อจะรู้เพียงแค่ interface เท่านั้น แต่ถ้าคุณใช้ protected ผมถามหน่อยว่า ถ้าเกิดคุณได้ code ที่เป็น .dll มา คุณจะรู้ส่วนของ interface ที่เป็น public เท่านั้น ในส่วนที่เป็น protected คุณอาจจะไม่รู้ แบบนี้คุณก็จะทำการ inherit ได้ไม่สมบูรณ์ ดังนั้นถ้าเลี่ยงการใช้ protected ได้ให้เลี่ยงครับ

ถ้าคุณ Inherit แบบ HAS-A เตรียมตัวรับความยุ่งยากได้เลย

    อย่างที่ผมเคยบอกว่า Implementation Inheritance นั้นรองรับความสัมพันธ์แบบ IS-A เท่านั้น ถ้าคุณใช้ แบบ HAS-A มันจะทำให้ในส่วนที่คุณไม่ต้องการนั้น แถมไปหลอกหลอนคุณด้วย มือใหม่สำหรับ OOP เจอปัญหานี้เยอะครับ มักจะไม่รู้ว่าอะไรควร Inherit และอะไรไม่ควร ผมให้หลัก IS-A กับ HAS-A ไปแล้ว ถ้าคุณประยุกต์ใช้ให้ถูกมักก็เกิดประโยชน์ แต่ถ้าไม่เป็นมันจะกลายเป็นโทษครับ

บทสรุป

   ผมคงไม่เห็นด้วยกับ Microsoft ที่ว่า Implementation Inheritance เป็น Devil ผมคงไม่สรุปแบบนั้น ผมขอพูดอย่างนี้ก็แล้วกันว่า Implementation Inheritance เป็นแค่เครื่องมือชนิดหนึ่ง ซึ่งเครื่องมือนี้ถูกออกแบบมาโดยเฉพาะ เช่นไขควง ถ้าคุณใช้มันไปขันน๊อทคงไม่มีอะไรดีกว่ามัน แต่ถ้าใช้มันในทางที่ผิดเช่นเอาไปตอกตะปู นอกจากไม่ค่อยได้เรื่องแล้ว ยังอาจตอกพลาดทำให้เราบาดเจ็บได้ เพราะฉะนั้นก่อนใช้คุณควรศึกษาเครื่องมือที่คุณใช้ให้ถ่องแท้ก่อน จะได้เป็นนายมัน ควมคุมมันอยู่