

OOP คืออะไร — เข้าใจ 3 แกนหลัก Encapsulation, Inheritance, Polymorphism
เข้าใจ OOP จริง ๆ ผ่านสามแนวคิดหลักที่ทุก codebase ใช้ — ซ่อนอะไร รับอะไรมา และแปลงร่างได้กี่แบบ
ถ้าเคยเปิด codebase ใหม่แล้วเจอ class เต็มไปหมด แล้วงงว่า “อันนี้ extend มาจากอันไหน? ทำไม method ชื่อเดียวกันถึงอยู่ต่าง class ได้?” — นั่นคือสัญญาณว่า OOP กำลังทำงานอยู่ แต่ละหลักการแก้ปัญหาคนละอย่าง และเข้าใจแยกกันได้ชัดกว่า
Object-Oriented Programming หรือ OOP ไม่ได้แค่เรื่อง “เขียนโค้ดใน class” แต่คือชุดแนวคิดที่ช่วยจัดระเบียบโปรแกรมขนาดใหญ่ให้ดูแลได้จริง หลักการหลักของ OOP มีสี่ข้อ — Encapsulation, Inheritance, Polymorphism และ Abstraction สามข้อแรกคือสิ่งที่จะเจอบ่อยที่สุดในเกือบทุกภาษา
🔒 Encapsulation — ซ่อนข้างใน เปิดแค่ที่จำเป็น#
ลองนึกถึง ATM ตู้นี้รู้วิธีตรวจยอด คำนวณเงิน เชื่อมระบบธนาคาร แต่เราในฐานะผู้ใช้แค่กดถอนเงินแล้วรับเงินออกมา ไม่รู้ว่าข้างในทำอะไรบ้าง — นั่นคือ Encapsulation
Encapsulation คือการซ่อนสถานะภายในของ object และเปิดเผยเฉพาะ interface สาธารณะที่จำเป็น
ใน code ทำได้ผ่าน access modifiers:
class BankAccount:
def __init__(self, balance):
self.__balance = balance # ตั้งใจให้เป็นข้อมูลภายใน ไม่ให้แตะจากข้างนอกตรง ๆ
def deposit(self, amount):
if amount > 0:
self.__balance += amount
def get_balance(self):
return self.__balancepython__balance ตั้งใจให้เป็นข้อมูลภายในของ object ไม่ใช่สิ่งที่โค้ดข้างนอกควรไปอ่านหรือแก้ตรง ๆ ใครอยากรู้ยอดให้เรียกผ่าน get_balance() แทน — นี่คือหัวใจของ Encapsulation: ภายนอกคุยกับ object ผ่าน method สาธารณะ ไม่ใช่ไปยุ่งกับ state ข้างในเอง
Encapsulation แก้ปัญหาอะไร?#
- ป้องกัน accidental modification — ถ้าทุกคนเข้าถึง field ตรง ๆ ได้ โค้ดส่วนใดก็อาจเปลี่ยนค่าโดยไม่ตั้งใจ
- เปลี่ยน internal implementation ได้โดยไม่กระทบภายนอก — อยากเปลี่ยนวิธีเก็บ balance จาก float เป็น Decimal ก็ทำได้ ตราบใดที่
get_balance()ยังคืนค่าเดิม - แต่ละ class รับผิดชอบ state ของตัวเอง — ไม่มี class ไหนแอบไปแก้ state ของ class อื่นได้โดยตรง
หมายเหตุ: Abstraction ≠ Encapsulation#
คนมักสับสนสองอันนี้ ตอบสั้น ๆ คือ:
- Abstraction — ซ่อนรายละเอียดที่ไม่จำเป็น เปิดเฉพาะ interface ที่ใช้งาน
- Encapsulation — ควบคุมการเข้าถึงข้อมูลภายใน object ผ่าน access control
Abstraction พูดถึงระดับ design ว่า interface ควรมีหน้าตาอย่างไร, Encapsulation พูดถึงกลไกที่ปกป้อง state ภายในไม่ให้ถูกเข้าถึงโดยตรง
Encapsulation ช่วยให้แต่ละ class ดูแลตัวเองได้ แต่ถ้า class หลายตัวมีโครงสร้างคล้ายกัน จะเริ่มใหม่ตั้งแต่ต้นทุกครั้งหรือ? นั่นคือที่มาของ Inheritance
🧬 Inheritance — รับมรดก ไม่ต้อง copy#
ถ้ามีระบบที่ต้องจัดการทั้ง Student และ Professor ทั้งคู่มีชื่อ มีอีเมล มี method greet() เหมือนกัน จะ copy โค้ดไปแปะทั้งสอง class ก็ทำได้ — แต่พอต้องแก้ greet() ต้องแก้สองที่ แล้วก็มักลืมแก้อีกอัน
Inheritance ช่วยให้ subclass รับ properties และ methods จาก superclass ได้โดยไม่ต้อง copy code
class Person:
def __init__(self, name, email):
self.name = name
self.email = email
def greet(self):
return f"สวัสดี ฉันชื่อ {self.name}"
class Student(Person):
def __init__(self, name, email, student_id):
super().__init__(name, email)
self.student_id = student_id
class Professor(Person):
def __init__(self, name, email, department):
super().__init__(name, email)
self.department = departmentpythonStudent และ Professor ต่างก็ได้ name, email และ greet() มาจาก Person โดยอัตโนมัติ แต่ละ class เพิ่มเฉพาะสิ่งที่ต่างกัน
ข้อดี#
- Code reuse — logic ที่ใช้ร่วมกันอยู่ที่เดียว แก้ที่เดียวกระทบทุก subclass
- Hierarchy ที่เป็นธรรมชาติ —
Studentเป็นPersonประเภทหนึ่ง ความสัมพันธ์แบบนี้ map ได้ดีใน code
ข้อควรระวัง#
Inheritance ที่ลึกเกินไป (หลาย level) ทำให้ trace โค้ดยาก บางครั้ง composition (การใส่ object เป็น field แทนการ inherit) เหมาะกว่า โดยเฉพาะเมื่อ relationship ไม่ได้เป็น “A เป็น B” อย่างชัดเจน เช่น Car กับ Engine — Car ไม่ได้ “เป็น” Engine แต่ Car “มี” Engine จึงเหมาะกับ composition มากกว่า
🎭 Polymorphism — ชื่อเดียว หลายรูปแบบ#
“Polymorphism” มาจากภาษากรีก แปลตรงตัวว่า “หลายรูปแบบ” ในโลก software หมายถึง object ต่างประเภทสามารถตอบสนองต่อ method ชื่อเดียวกันได้ โดยแต่ละประเภทมี behavior เป็นของตัวเอง ลองดูตัวอย่างนี้:
class Animal:
def speak(self):
return "..."
class Dog(Animal):
def speak(self):
return "โฮ่ง!"
class Cat(Animal):
def speak(self):
return "เมียว~"
animals = [Dog(), Cat(), Dog()]
for animal in animals:
print(animal.speak())
# โฮ่ง!
# เมียว~
# โฮ่ง!pythonแม้ลูป iterate ผ่าน Animal แต่แต่ละตัวเรียก speak() ของตัวเองได้ถูก — นี่คือ Polymorphism: method ชื่อเดียวกัน ทำงานต่างกันในแต่ละ class ตัวอย่างนี้เป็น runtime polymorphism แบบ method overriding
สองประเภทหลัก#
| ประเภท | เรียกว่า | resolve เมื่อไหร่ | ตัวอย่าง |
|---|---|---|---|
| Compile-time | Overloading | ตอน compile | function ชื่อเดียว parameter ต่างกัน |
| Runtime | Overriding | ตอน run | subclass override method ของ superclass |
ใน C# จะเห็น keyword virtual ที่ base class method และ override ใน derived class — เป็น syntax ที่บังคับให้ประกาศชัดเจนว่าตั้งใจ override:
class Animal {
public virtual string Speak() => "...";
}
class Dog : Animal {
public override string Speak() => "โฮ่ง!";
}csharpทำไม Polymorphism ถึงมีประโยชน์#
สมมติมีระบบ payment ที่รองรับทั้ง Credit Card, PromptPay และ Crypto ถ้าไม่มี polymorphism ต้องเขียน if/else ยาวเพื่อเช็คประเภทแล้วเรียก method ที่ถูกต้อง — แต่ถ้าทุก payment type implement interface เดียวกัน (process_payment()) โค้ดส่วนกลางเรียกได้เลยโดยไม่สนว่าข้างในคือประเภทไหน
เพิ่ม payment type ใหม่ก็แค่เพิ่ม class ใหม่ ไม่ต้องแตะโค้ดส่วนกลาง
🤝 สามแนวคิดนี้ทำงานร่วมกัน#
ในชีวิตจริง ทั้งสามแนวคิดนี้ไม่ได้ใช้แยกกัน:
- Encapsulation ทำให้แต่ละ class ดูแล state ของตัวเองได้ ไม่ให้ภายนอกยุ่ง
- Inheritance ทำให้แชร์โครงสร้างร่วมกันโดยไม่ copy
- Polymorphism ทำให้ใช้ interface เดียวกับ object หลายประเภท โดยแต่ละประเภทมี behavior ของตัวเอง
ระบบที่ออกแบบดีมักใช้ทั้งสามอย่างประกอบกัน เช่น Payment เป็น abstract class (inheritance + polymorphism) ที่ซ่อน internal logic ของแต่ละ provider ไว้ข้างใน (encapsulation)
⚖️ เมื่อไหร่ควรใช้ และเมื่อไหร่ไม่ควรใช้ OOP#
OOP เหมาะกับระบบที่:
- มี entity หลายประเภทที่มีความสัมพันธ์กัน เช่น User, Admin, Guest
- มี behavior ที่ต้อง reuse ข้าม entity หลายตัว
- ต้องการขยาย (extend) ในอนาคตโดยไม่แตะโค้ดเดิม
OOP อาจไม่ใช่ทางเลือกที่ดีที่สุดเมื่อ:
- งานเป็น data transformation ตรง ๆ เช่น ETL pipeline, script ง่าย ๆ — functional style อาจสะอาดกว่า
- ทีมยังไม่คุ้นเคย การฝืนใช้ OOP โดยออกแบบไม่ดีอาจทำให้เกิด hierarchy ที่ซับซ้อนเกินจำเป็น
ถ้าอ่านมาถึงตรงนี้แล้วรู้สึกว่า “โอ้ นี่คือสิ่งที่เจอใน codebase ทุกวัน แต่ไม่รู้ชื่อ” — ยินดีต้อนรับ ตอนนี้คุณรู้ชื่อแนวคิดพวกนี้แล้ว และพอเห็นภาพสามหลักการนี้ชัดขึ้น การอ่าน design patterns ก็จะเริ่มชัดและสมเหตุสมผลขึ้นเอง
สามแนวคิดนี้เป็นฐานของ design patterns หลายอย่างที่ใช้กันจริงใน production เช่น Strategy, Template Method, Factory — ซึ่งล้วนยืมไอเดียจาก polymorphism และ inheritance ไปต่อยอด
ลองเปิด codebase ที่ใช้อยู่แล้วลอง trace ว่า pattern ไหนซ่อน inheritance หรือ polymorphism ไว้ข้างใน — คำตอบมักอยู่ใกล้กว่าที่คิด
😎 ☕