การพ้องรูป (Polymorphism)
วันนี้เรามาเรียนรู้เกี่ยวกับการพ้องรูป หรือ Polymorphism ซึ่งเป็นหนึ่งในแนวคิดสำคัญของการเขียนโปรแกรมเชิงวัตถุ (OOP) ใน Java กัน
การพ้องรูปคืออะไร?
การพ้องรูป หมายถึง ความสามารถของวัตถุในการมีหลายรูปแบบ หรือการที่เมธอดเดียวกันสามารถทำงานได้หลายรูปแบบ ขึ้นอยู่กับวัตถุที่เรียกใช้งาน
ลองนึกภาพปุ่มเปิด-ปิดบนรีโมท 🎛️ ปุ่มเดียวกันนี้อาจจะเปิด-ปิดทีวี วิทยุ หรือแอร์ได้ ขึ้นอยู่กับว่าคุณกำลังใช้รีโมทควบคุมอุปกรณ์อะไรอยู่
ทำไมการพ้องรูปถึงสำคัญ?
- ทำให้โค้ดมีความยืดหยุ่นมากขึ้น
- ลดความซับซ้อนของโค้ด
- ทำให้การเพิ่มฟังก์ชันใหม่ทำได้ง่ายขึ้น
- ช่วยให้เราสามารถทำงานกับคลาสที่มีความสัมพันธ์กันได้ง่ายขึ้น
ประเภทของการพ้องรูป
Java มีการพ้องรูป 2 ประเภทหลัก:
- การพ้องรูปแบบคอมไพล์ไทม์ (Compile-time Polymorphism)
- การพ้องรูปแบบรันไทม์ (Runtime Polymorphism)
มาดูแต่ละประเภทกัน
1. การพ้องรูปแบบคอมไพล์ไทม์ (Method Overloading)
การพ้องรูปแบบนี้เกิดขึ้นเมื่อเรามีหลายเมธอดในคลาสเดียวกันที่มีชื่อเหมือนกัน แต่พารามิเตอร์ต่างกัน:
public class คำนวณ {
public int บวก(int a, int b) {
return a + b;
}
public double บวก(double a, double b) {
return a + b;
}
public int บวก(int a, int b, int c) {
return a + b + c;
}
}
public class ทดสอบการบวก {
public static void main(String[] args) {
คำนวณ เครื่องคิดเลข = new คำนวณ();
System.out.println(เครื่องคิดเลข.บวก(5, 3)); // เรียกใช้เมธอดแรก
System.out.println(เครื่องคิดเลข.บวก(4.5, 3.2)); // เรียกใช้เมธอดที่สอง
System.out.println(เครื่องคิดเลข.บวก(1, 2, 3)); // เรียกใช้เมธอดที่สาม
}
}2. การพ้องรูปแบบรันไทม์ (Method Overriding)
การพ้องรูปแบบนี้เกิดขึ้นเมื่อคลาสลูกมีเมธอดที่มีชื่อและพารามิเตอร์เหมือนกับเมธอดในคลาสแม่:
class สัตว์ {
public void ร้อง() {
System.out.println("สัตว์กำลังร้อง");
}
}
class สุนัข extends สัตว์ {
@Override
public void ร้อง() {
System.out.println("โฮ่ง! โฮ่ง!");
}
}
class แมว extends สัตว์ {
@Override
public void ร้อง() {
System.out.println("เหมียว! เหมียว!");
}
}
public class ทดสอบการร้อง {
public static void main(String[] args) {
สัตว์ สัตว์1 = new สัตว์();
สัตว์ สุนัข1 = new สุนัข();
สัตว์ แมว1 = new แมว();
สัตว์1.ร้อง(); // แสดง: สัตว์กำลังร้อง
สุนัข1.ร้อง(); // แสดง: โฮ่ง! โฮ่ง!
แมว1.ร้อง(); // แสดง: เหมียว! เหมียว!
}
}การใช้ Interfaces เพื่อสร้างการพ้องรูป
Interfaces เป็นอีกวิธีหนึ่งในการสร้างการพ้องรูป:
interface สามารถบิน {
void บิน();
}
class นก implements สามารถบิน {
public void บิน() {
System.out.println("นกกำลังบินด้วยปีก");
}
}
class เครื่องบิน implements สามารถบิน {
public void บิน() {
System.out.println("เครื่องบินกำลังบินด้วยเครื่องยนต์");
}
}
public class ทดสอบการบิน {
public static void main(String[] args) {
สามารถบิน นกน้อย = new นก();
สามารถบิน เครื่องบินโบอิ้ง = new เครื่องบิน();
นกน้อย.บิน(); // แสดง: นกกำลังบินด้วยปีก
เครื่องบินโบอิ้ง.บิน(); // แสดง: เครื่องบินกำลังบินด้วยเครื่องยนต์
}
}ประโยชน์ของการพ้องรูป
- ความยืดหยุ่น: สามารถใช้คลาสแม่เพื่ออ้างถึงวัตถุของคลาสลูกได้
- การขยายได้: เพิ่มคลาสใหม่ที่สืบทอดจากคลาสแม่ได้โดยไม่ต้องแก้ไขโค้ดเดิม
- การบำรุงรักษา: ทำให้โค้ดเป็นระเบียบและง่ายต่อการบำรุงรักษา
ตัวอย่างการใช้งานจริง
ลองมาสร้างระบบคำนวณพื้นที่รูปทรงต่างๆ โดยใช้การพ้องรูปกัน:
abstract class รูปทรง {
abstract double คำนวณพื้นที่();
}
class วงกลม extends รูปทรง {
private double รัศมี;
public วงกลม(double รัศมี) {
this.รัศมี = รัศมี;
}
@Override
double คำนวณพื้นที่() {
return Math.PI * รัศมี * รัศมี;
}
}
class สี่เหลี่ยม extends รูปทรง {
private double ความกว้าง;
private double ความยาว;
public สี่เหลี่ยม(double ความกว้าง, double ความยาว) {
this.ความกว้าง = ความกว้าง;
this.ความยาว = ความยาว;
}
@Override
double คำนวณพื้นที่() {
return ความกว้าง * ความยาว;
}
}
public class โปรแกรมคำนวณพื้นที่ {
public static void main(String[] args) {
รูปทรง[] รูปทรงต่างๆ = new รูปทรง[3];
รูปทรงต่างๆ[0] = new วงกลม(5);
รูปทรงต่างๆ[1] = new สี่เหลี่ยม(4, 5);
รูปทรงต่างๆ[2] = new วงกลม(3);
for (รูปทรง รูป : รูปทรงต่างๆ) {
System.out.println("พื้นที่: " + รูป.คำนวณพื้นที่());
}
}
}สรุป
การพ้องรูปเป็นแนวคิดที่ทรงพลังใน OOP ช่วยให้เราสร้างโค้ดที่ยืดหยุ่น ขยายได้ง่าย และบำรุงรักษาได้ดี การเข้าใจและใช้การพ้องรูปอย่างเหมาะสมจะช่วยให้คุณสามารถออกแบบและเขียนโปรแกรมที่มีประสิทธิภาพและยืดหยุ่นมากขึ้น