All About OOP – ตอนที่ 2 เจาะลึก Inheritance เมื่อคลาสมีผู้สืบทอดได้

อ่านตอนก่อนหน้านี้ได้ที่

developer

บทความชุด: All About Object-Orient Programming

รวมบทความเจาะลึกเกี่ยวกับการเขียนโปรแกรมเชิงวัตถุ ตั้งแต่แนวคิด วิธีการใช้งาน ตัวอย่างและหลักการใช้ต่างๆ เช่น S.O.L.I.D หรือการใช้ Design Pattern

ในโลก OOP เกิดขึ้นจากแนวความคิดหลักคือ “reuse เอากลับมาใช้ซ้ำ” ซึ่งเป็นสาเหตุที่ทำให้เกิดคอนเซ็ปที่สองตามมากคือ “ความเป็น abstract”

ย้อนอดีตกันนิดนึง

แนว คิดของ Object Oriented นั้นมีมานานมากแล้ว ประมาณปี 1960 (ใครเกิดทันบ้าง แน่นอนว่าเราเกิดไม่ทัน ฮา) โดยนักวิทยาศาสตร์คอมพิวเตอร์ 2 คนคือ Ole-Johan Dahl และ Kristen Nygaard ในยุคนั้นการเขียนโปรแกรมจะเขียนกับแบบ imperative แบบบน-ลง-ล่าง เขียนแบบสอนคอมพิวเตอร์เป็นขั้นๆ แบบ how-to … ทั้งสองคนต้องการสร้างภาษาคอมพิวเตอร์ใหม่ชื่อว่า SIMULA I ซึ่งเป็นภาษาสำหรับการทำ simulation

หลังจากทำเสร็จทั้งสองก็มีแนวคิด ในการออกแบบภาษาคอมพิวเตอร์แบบใหม่ที่ใช้งานได้รวมๆ ทุกรูปแบบ ซึ่งในสมัยนั้นภาษาคอมพิวเตอร์ภาษาหนึ่งมักจะถูกออกแบบมาสำหรับงานที่เฉพาะ เจาะจงแบบหนึ่งเท่านั้น เช่นงานด้านวิทยาศาสตร์และคณิตศาสตร์ก็จะใช้ภาษา FORTRAN, งานธุรกิจการเงินก็จะใช้COBAL, การศึกษา AI ก็จะใช้ LISP ไม่เหมือนทุกวันที่ที่ภาษาหนึ่งภาษาแทบจะเอาอยู่กับงานเกือบทุกรูปแบบ

ทั้ง คู่เลยยกเอาภาษา SIMULA I มาปัดฝุ่นซะใหม่เรียกว่า SIMULA 67 โดยมองข้อมูลและของต่างๆ ในโปรแกรมเป็น “วัตถุ” มีหลักการ โน่น-นี่-นั่น มากมายแต่สิ่งที่สำคัญที่สุดคือภาษานี้เป็นภาษาที่สอนให้ทุกคนรู้จักกับคำ ว่า class … แต่เป็นที่น่าเสียดายว่าภาษานี้มันไม่ค่อยได้รับความนิยมเท่าไหร่ แต่ตัวภาษาที่ทำให้คอนเซ็ปภาษาแบบ OOP ดังขึ้นมาคือภาษา Smalltalk ของบริษัท Xerox ที่รับแนวคิด OOP ของ SIMULA มาเต็มที่

แล้วสาเหตุอะไรที่ภาษาต้นแบบไม่ดัง แต่ Smalltalk ก็ยังเลือกมาใช้ล่ะ

นั่นก็เพราะภาษา Smalltalk โชว์จุดขายในการทำ interface ส่วนหน้าจอที่ผู้ใช้เห็นด้วยแนวคิดแบบ GUI หรือ Graphic User Interface .. มาร์คตรงคำว่า Graphic เอาไว้เลย ในสมัยนั้นคอมพิวเตอร์แสดงผลได้แค่แบบ Command Line หรือหน้าขอสีดำๆ ที่มีแต่ตัวอักษร ต้องสั่งงานคอมพิวเตอร์โดยการพิมพ์คำสั่งเอาเท่านั้น และเจ้านี่เองก็เป็นต้นแบบให้ Apple หยิบเอาแนวคิดนี้มาทำ Apple Lisa ซึ่งเป็น GUI OS ตัวชูโรง …ยังไม่หมดแค่นั้น แน่นอนว่ามีหรือที่ Microsoft จะอยู่เฉย Apple ลอกได้ฉันก็ลอกได้ เลยออกมาเป็น Windows ที่เราใช้กันแบบทุกวันนี้

และสาเหตุที่ Smalltalk หยิบแนวทาง Object Oriented ไปใช้ก็คือ interface แบบกราฟิกน่ะ มันประกอบด้วยคอมโพเนนท์ ส่วนประกอบหลายอย่าง เหมือนกันวัตถุในโลกจริง

แนว ทางของ OOP เลยเข้าทางภาษาที่ต้องการ UI แบบกราฟิกพอดี เพราะถ้าลองสังเกตดีๆ ส่วนประกอบต่างๆ ของ GUI นั้นคือหน้าต่างเฟรม (ที่ปัจจุบันเราเรียกกันว่า windows) ตัวอักษรพวกลาเบลต่างๆ ปุ่ม ปุ่ม ปุ่ม ปุ่ม และ ปุ่มสารพัดชนิด ซึ่งภาษา Smalltalk เรียกเจ้าคอมโพเนนท์พวกนี้รวมๆ ว่า “Object”  … ไม่ว่าจะคอมโพเนนท์ชิ้นไหน พวกแกทั้งหมดคือส่วนประกอบของ GUI ทั้งสิ้น แต่ภาษาโปรแกรมแบบเดิมในตอนนั้น (ภาษาแนว imperative) ไม่ตอบโจทย์การเขียน เพราะสมมุติว่าเราต้องการสร้างอ๊อบเจคของ “button” ขึ้นมา แต่ปุ่มมันก็ไม่ได้มีรูปร่างแบบเดียวกันทั้งระบบ ทั้งตั้งแต่ ปุ่มใหญ่ ปุ่มเล็ก สีเขียว สีแดง สีเทา บางอันเป็นไอค่อน บางอันเป็นตัวอักษร หรือทั้งไอค่อนทั้งตัวอักษรรวมกันอยู่ในปุ่มเดียวกันก็มี ถ้าเราใช้ภาษาโปรแกรมแบบเดิมสร้างเจ้าพวกปุ่มมากมายพวกนี้ขึ้นมา แน่นอนว่าจะต้องมีส่วนของโค้ดที่ “ซ้ำกัน” อยู่มากแน่ๆ (ก็สร้างให้เสร็จสักปุ่มแล้วถ้าอยากได้อีกก็จะเป็นอะไรได้ล่ะ นอกจาก copy-paste-modify ฮา) และแม้ว่าภาษาพวกนี้จะมี function เอาไว้ใช้จัดการกับโค้ดที่ซ้ำซ้อน แต่ในเคสแบบนี้ function ก็ไม่ได้ช้วยอะไรเรามากหรอก

แต่สำหรับ OOP นั้นมันรองรับวิธีเขียนโค้ดประมาณนี้ได้ดี เพราะเป็นการจำลองวัตถุในโลกจริงมาไว้ในรูปแบบของโค้ดโปรแกรม โดยเฉพาะแนวคิด Inheritance หรือที่ภาษาไทยแปลว่า “การสืบทอด” คุณสมบัติจากคลาสๆ หนึ่งไปสู่อีกคลาสได้อย่างง่ายดาย (ถ้าเขียนเป็น)

อย่าง ไรก็ตาม ตัวภาษา Smalltalk ก็ยังไม่ค่อยได้รับความนิยมเพราะว่ามันต้องการพลังของ hardware ในการกระมวลผลสูงสุดๆ เพราะนอกจากคอมพิวเตอร์จะต้องประมวลผลส่วนหลักของโปรแกรมแล้ว output ที่ปกติก็ทำกันแค่ปริ๊นผลลัพท์ออกมาก็ยังต้องมาประมวลผลให้ออกมาในรูป Graphic อีกด้วย … แต่สำหรับยุคปัจจุบันกำลังประมวลผลของเครื่องที่เร็วกว่าสมัยก่อนหลายร้อย เท่าทำให้มันไม่ใช่ปัญหาอีกแล้ว ภาษาหลายๆ ภาษาที่สืบทอดแนวคิดของ Smalltalk มาเช่น C++ C# Java จึงโด่งดังในยุคนี้ได้

แนวทางพื้นฐาน 4 อย่างในการ reuse ของ OOP

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

คำเตือน: หัวข้อ Abstraction, Inheritance และ Polymorphism เป็นหัวข้อที่อธิบาย/เข้าใจยาก แต่จะพยายามเขียนให้เข้าใจง่ายที่สุด … แต่ถ้าคุณอ่านแล้วไม่เข้าใจมันจริงๆ เราเข้าใจคุณ (เพราะครั้งหนึ่งเราก็เคยไม่เข้าใจมัน) ให้อ่านๆ ไปก่อนแล้วในบทความหลังๆ จะเป็นตัวอย่างการใช้ของเจ้าพวกนี้ แต่สำหรับบทความวันนี้เอาทฤษฎีไปก่อนนะ (ฮา)

1. Abstraction

หัวใจหลักของ OOP ที่เข้าใจย๊าก~ยาก จนไม่รู้ว่าตกลงมันเป็นจุดแข็งหรือจุดอ่อนของแนวคิดนี้กันแน่ (ฮา)

แปลเป็นภาษาไทยว่า “นามธรรม” หมายถึง ไร้รูป ไร้ลักษณ์ บรรลุ นิพาน เดี๋ยวๆ! คือเป็นสิ่งที่ทุกคนรู้ แต่อธิบายไม่ถูก แถมไม่แน่ใจด้วยสิ่งที่เรารู้แล้วคนอื่นรู้น่ะ มันจะตรงกันรึเปล่า! … จะเห็นว่าคอนเซ็ปนี้แค่อธิบายมันก็ “แอ็บสเตร็ก” มากๆ แล้ว ไม่น่าแปลกใจที่นักศึกษาที่เรียน OOP แรกๆ จะอ่านมันไม่เข้าใจแล้วก็ข้ามมันไป ทั้งที่มันคือประเด็นหลักเลย

พอๆ เอาใหม่! กลับมาเข้าเรื่องภาษาโปรแกรม … ตอนที่เราเขียนโปรแกรมแบบ imperative แบบเดิมน่ะ ด้วยตัวภาษาที่ต้องสั่งงานคอมพิวเตอร์ทุกขั้นตอน แบบขอละเอียดมากๆ อยากได้อะไรเราต้องรู้วิธีการคิดทุกอย่างถึงจะเริ่มเขียนได้ แล้วยิ่งอาจารย์ในชั้นเรียน Fundamental Programming เขียนโปรแกรมเบื้องต้นมักจะชอบบอกนักเรียนด้วยว่า จงรู้วิธีการแก้ปัญหาก่อน เขียนโพลว์ชาร์ตและคิดอัลกอริทึมก่อนจะเริ่มเขียนโค้ดนะ ทำให้นักเรียนมักจะมีความคิดฝั่งเข้าหัวเลยว่า จะเขียนโปรแกรมอะไรก็ตามคิดวิธีให้สำเร็จ 100% ก่อน วิธีการแบบนี้เราเรียกว่าแนว “Real” หรือ “Concrete”

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

Object Oriented เลยมีแนวคิดว่า ก็ถ้ามันยังคิดไม่ออก หรือไม่รู้วิธีตอนนี้ ก็ไม่ต้องเขียนก็ได้ ติ๊ต่างว่ามันทำได้ก็แล้วกัน (แล้วค่อยกลับมาเขียนในอนาคต)

อืม ดูเป็นไอเดียที่ดีเนอะ เช่นกรณีของการออกแบบส่วนติดต่อกับผู้ใช้เมื่อกี้ โปรแกรมของเรามีทั้งปุ่ม ทั้งกล่องข้อความ แท็ป แจ้งเตือน หรืออะไรมากมาย อ๊อบเจคพวกนี้สามารถเอามาปะๆ รวมกันแล้วเขียนโค้ดลงไปทีละชิ้นว่าจะให้ทำงานอย่างไร ใช่แล้ว…วัตถุมีอยู่แล้วนะ! แต่เราเขียนวิธีการทำงานของมันตามหลังได้!

เบื้อง หลังอ๊อบเจคพวกนี้คือแนวคิดแบบ Abstract นั่นคือคนคิดปุ่ม คิดกล่องข้อความเขาไม่รู้หรอกว่าเวลาโปรแกรมเมอร์แบบเราๆ เอาส่วนประกอบพวกนี้มารวมๆ กันแล้วมันจะต้องทำงานอย่างไร ดังนั้นเขาเลยละส่วนที่ไม่รู้เอาไว้ โดยหวังว่าคนที่เอาไปใช้จะช่วยเขียนโค้ดส่วนนี้เ