SiamCafe.net Blog
Technology

OOP Concepts คือ — หลักการ Object-Oriented Programming ครบทั้ง 4 Pillars

oop concepts คอ
oop concepts คือ | SiamCafe Blog
2026-04-07· อ. บอม — SiamCafe.net· 1,492 คำ

OOP คืออะไรและทำไมต้องใช้

OOP (Object-Oriented Programming) คือแนวคิดการเขียนโปรแกรมที่จัดโครงสร้างโค้ดเป็น objects ซึ่งรวม data (attributes) และ behavior (methods) ไว้ด้วยกัน แทนที่จะเขียนโค้ดเป็นลำดับขั้นตอนจากบนลงล่างแบบ procedural programming OOP จัดการโค้ดเป็นกลุ่มของ objects ที่มีปฏิสัมพันธ์กัน

ข้อดีหลักของ OOP คือ Reusability ที่สามารถนำ class ไปใช้ซ้ำได้หลายที่ Maintainability ที่แก้ไขได้ง่ายเพราะโค้ดถูกจัดกลุ่มอย่างมีระเบียบ Scalability ที่ขยายระบบได้ง่ายโดยเพิ่ม class ใหม่ Modularity ที่แบ่งปัญหาใหญ่เป็นส่วนเล็กๆที่จัดการง่าย และ Collaboration ที่ทีมสามารถทำงานคนละ class ได้โดยไม่กระทบกัน

ภาษาที่รองรับ OOP ได้แก่ Python, Java, C++, C#, TypeScript, Ruby, PHP, Kotlin, Swift, Go (บางส่วน) และ Rust (บางส่วน) แต่ละภาษามีวิธี implement OOP แตกต่างกัน บางภาษาเป็น pure OOP เช่น Java ที่ทุกอย่างต้องอยู่ใน class บางภาษาเป็น multi-paradigm เช่น Python ที่ใช้ OOP หรือ functional ก็ได้

OOP มี 4 หลักการพื้นฐาน (Four Pillars) คือ Encapsulation, Abstraction, Inheritance และ Polymorphism ทั้ง 4 หลักการนี้ทำงานร่วมกันเพื่อสร้างโค้ดที่มีคุณภาพดี

4 หลักการพื้นฐานของ OOP

อธิบายหลักการแต่ละข้อพร้อมตัวอย่างโค้ด

# 4 Pillars of OOP — ตัวอย่างด้วย Python
#
# === 1. Encapsulation ===
# ซ่อนรายละเอียดภายในและเปิดเผยเฉพาะส่วนที่จำเป็น
class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner          # public
        self._account_id = "ACC001" # protected (convention)
        self.__balance = balance    # private (name mangling)
    
    def deposit(self, amount):
        if amount <= 0:
            raise ValueError("Amount must be positive")
        self.__balance += amount
        return self.__balance
    
    def withdraw(self, amount):
        if amount > self.__balance:
            raise ValueError("Insufficient funds")
        self.__balance -= amount
        return self.__balance
    
    @property
    def balance(self):
        return self.__balance

# === 2. Abstraction ===
# ซ่อนความซับซ้อน แสดงเฉพาะ interface ที่จำเป็น
from abc import ABC, abstractmethod

class PaymentGateway(ABC):
    @abstractmethod
    def process_payment(self, amount):
        pass
    
    @abstractmethod
    def refund(self, transaction_id):
        pass

class StripeGateway(PaymentGateway):
    def process_payment(self, amount):
        return {"status": "success", "provider": "stripe", "amount": amount}
    
    def refund(self, transaction_id):
        return {"status": "refunded", "tx_id": transaction_id}

# === 3. Inheritance ===
# สืบทอด properties และ methods จาก parent class
class Animal:
    def __init__(self, name, sound):
        self.name = name
        self.sound = sound
    
    def speak(self):
        return f"{self.name} says {self.sound}"

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name, "Woof")
        self.breed = breed
    
    def fetch(self, item):
        return f"{self.name} fetches the {item}"

class Cat(Animal):
    def __init__(self, name):
        super().__init__(name, "Meow")

# === 4. Polymorphism ===
# Object ต่างชนิดตอบสนองต่อ method เดียวกันต่างวิธี
class Shape(ABC):
    @abstractmethod
    def area(self):
        pass
    
    @abstractmethod
    def perimeter(self):
        pass

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    def area(self):
        return 3.14159 * self.radius ** 2
    def perimeter(self):
        return 2 * 3.14159 * self.radius

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    def area(self):
        return self.width * self.height
    def perimeter(self):
        return 2 * (self.width + self.height)

# Polymorphism in action
shapes = [Circle(5), Rectangle(4, 6), Circle(3)]
for s in shapes:
    print(f"{s.__class__.__name__}: area={s.area():.2f}")

Encapsulation และ Abstraction ด้วย Python

ตัวอย่างเชิงลึกของ Encapsulation และ Abstraction ในโปรเจกต์จริง

#!/usr/bin/env python3
# ecommerce_oop.py — E-commerce System ด้วย OOP
from abc import ABC, abstractmethod
from datetime import datetime
from typing import Optional
from dataclasses import dataclass, field

# --- Encapsulation: Product class ---
@dataclass
class Product:
    name: str
    price: float
    stock: int
    _id: str = field(default_factory=lambda: f"PRD-{datetime.now().strftime('%H%M%S')}")
    
    def update_price(self, new_price: float):
        if new_price < 0:
            raise ValueError("Price cannot be negative")
        self.price = new_price
    
    def reduce_stock(self, qty: int):
        if qty > self.stock:
            raise ValueError(f"Only {self.stock} items available")
        self.stock -= qty

# --- Abstraction: Payment interface ---
class PaymentProcessor(ABC):
    @abstractmethod
    def charge(self, amount: float, token: str) -> dict:
        pass
    
    @abstractmethod
    def refund(self, tx_id: str, amount: float) -> dict:
        pass

class StripeProcessor(PaymentProcessor):
    def __init__(self, api_key: str):
        self.__api_key = api_key  # Encapsulated
    
    def charge(self, amount: float, token: str) -> dict:
        # Stripe API call (simplified)
        return {"tx_id": f"ch_{token[:8]}", "amount": amount, "status": "paid"}
    
    def refund(self, tx_id: str, amount: float) -> dict:
        return {"tx_id": tx_id, "refunded": amount, "status": "refunded"}

class PayPalProcessor(PaymentProcessor):
    def __init__(self, client_id: str, secret: str):
        self.__client_id = client_id
        self.__secret = secret
    
    def charge(self, amount: float, token: str) -> dict:
        return {"tx_id": f"pp_{token[:8]}", "amount": amount, "status": "paid"}
    
    def refund(self, tx_id: str, amount: float) -> dict:
        return {"tx_id": tx_id, "refunded": amount, "status": "refunded"}

# --- Encapsulation: Shopping Cart ---
class ShoppingCart:
    def __init__(self):
        self.__items: list[tuple[Product, int]] = []
    
    def add_item(self, product: Product, qty: int = 1):
        if qty > product.stock:
            raise ValueError(f"Only {product.stock} {product.name} available")
        # Check if already in cart
        for i, (p, q) in enumerate(self.__items):
            if p._id == product._id:
                self.__items[i] = (p, q + qty)
                return
        self.__items.append((product, qty))
    
    def remove_item(self, product_id: str):
        self.__items = [(p, q) for p, q in self.__items if p._id != product_id]
    
    @property
    def total(self) -> float:
        return sum(p.price * q for p, q in self.__items)
    
    @property
    def item_count(self) -> int:
        return sum(q for _, q in self.__items)
    
    def checkout(self, processor: PaymentProcessor, token: str) -> dict:
        if not self.__items:
            raise ValueError("Cart is empty")
        
        # Reduce stock
        for product, qty in self.__items:
            product.reduce_stock(qty)
        
        # Process payment (Polymorphism)
        result = processor.charge(self.total, token)
        
        order = {
            "items": [(p.name, q, p.price) for p, q in self.__items],
            "total": self.total,
            "payment": result,
            "date": datetime.now().isoformat(),
        }
        
        self.__items.clear()
        return order

# ใช้งาน
laptop = Product("MacBook Pro", 59900, 10)
mouse = Product("MX Master 3S", 3490, 50)

cart = ShoppingCart()
cart.add_item(laptop, 1)
cart.add_item(mouse, 2)
print(f"Cart: {cart.item_count} items, Total: {cart.total:,.0f} THB")

stripe = StripeProcessor("sk_test_xxx")
order = cart.checkout(stripe, "tok_visa_4242")
print(f"Order: {order['payment']['status']}")

Inheritance และ Polymorphism ในทางปฏิบัติ

ตัวอย่าง Inheritance หลายแบบและ Polymorphism

#!/usr/bin/env python3
# inheritance_demo.py — Inheritance Patterns

# === Single Inheritance ===
class Vehicle:
    def __init__(self, brand, model, year):
        self.brand = brand
        self.model = model
        self.year = year
        self._mileage = 0
    
    def drive(self, km):
        self._mileage += km
        return f"Drove {km}km. Total: {self._mileage}km"
    
    def __str__(self):
        return f"{self.year} {self.brand} {self.model}"

class ElectricCar(Vehicle):
    def __init__(self, brand, model, year, battery_kwh):
        super().__init__(brand, model, year)
        self.battery_kwh = battery_kwh
        self.charge_level = 100
    
    def drive(self, km):
        consumption = km * 0.15  # kWh per km
        if consumption > self.charge_level * self.battery_kwh / 100:
            raise ValueError("Not enough charge")
        self.charge_level -= consumption / self.battery_kwh * 100
        return super().drive(km) + f" (Charge: {self.charge_level:.0f}%)"
    
    def charge(self, percent=100):
        self.charge_level = min(100, self.charge_level + percent)

# === Multiple Inheritance (Mixin Pattern) ===
class GPSMixin:
    def get_location(self):
        return {"lat": 13.7563, "lng": 100.5018}
    
    def navigate(self, destination):
        return f"Navigating to {destination}"

class BluetoothMixin:
    def connect_device(self, device_name):
        return f"Connected to {device_name}"
    
    def play_music(self, song):
        return f"Playing: {song}"

class SmartCar(ElectricCar, GPSMixin, BluetoothMixin):
    def __init__(self, brand, model, year, battery_kwh):
        super().__init__(brand, model, year, battery_kwh)
        self.autopilot = False
    
    def enable_autopilot(self):
        self.autopilot = True
        location = self.get_location()
        return f"Autopilot ON at {location}"

# === Composition over Inheritance ===
class Engine:
    def __init__(self, horsepower, fuel_type):
        self.horsepower = horsepower
        self.fuel_type = fuel_type
    
    def start(self):
        return f"{self.fuel_type} engine ({self.horsepower}hp) started"

class Transmission:
    def __init__(self, type_name, gears):
        self.type_name = type_name
        self.gears = gears
        self.current_gear = 0
    
    def shift(self, gear):
        if 0 <= gear <= self.gears:
            self.current_gear = gear
            return f"Shifted to gear {gear}"

class Car:
    def __init__(self, brand, engine: Engine, transmission: Transmission):
        self.brand = brand
        self.engine = engine          # Composition
        self.transmission = transmission  # Composition
    
    def start_drive(self):
        self.engine.start()
        self.transmission.shift(1)
        return f"{self.brand} ready to drive"

# === Method Resolution Order (MRO) ===
print(SmartCar.__mro__)
# SmartCar -> ElectricCar -> Vehicle -> GPSMixin -> BluetoothMixin -> object

# ใช้งาน
tesla = SmartCar("Tesla", "Model 3", 2024, 75)
print(tesla.drive(50))
print(tesla.navigate("Central World"))
print(tesla.connect_device("AirPods"))
print(tesla.enable_autopilot())

SOLID Principles สำหรับ OOP ที่ดี

5 หลักการ SOLID ที่ช่วยให้เขียน OOP ได้ดีขึ้น

#!/usr/bin/env python3
# solid_principles.py — SOLID Principles Examples

# === S — Single Responsibility Principle ===
# แต่ละ class ควรมีหน้าที่เดียว

# BAD: class ทำหลายหน้าที่
class UserBad:
    def save_to_db(self): pass
    def send_email(self): pass
    def generate_report(self): pass

# GOOD: แยก responsibilities
class User:
    def __init__(self, name, email):
        self.name = name
        self.email = email

class UserRepository:
    def save(self, user: User): pass
    def find(self, user_id: str): pass

class EmailService:
    def send(self, to: str, subject: str, body: str): pass

# === O — Open/Closed Principle ===
# เปิดสำหรับ extension, ปิดสำหรับ modification
from abc import ABC, abstractmethod

class Discount(ABC):
    @abstractmethod
    def calculate(self, price: float) -> float:
        pass

class PercentageDiscount(Discount):
    def __init__(self, percent: float):
        self.percent = percent
    def calculate(self, price: float) -> float:
        return price * (1 - self.percent / 100)

class FixedDiscount(Discount):
    def __init__(self, amount: float):
        self.amount = amount
    def calculate(self, price: float) -> float:
        return max(0, price - self.amount)

class BuyOneGetOneFree(Discount):
    def calculate(self, price: float) -> float:
        return price / 2

# === L — Liskov Substitution Principle ===
# Subclass ต้องแทนที่ parent ได้โดยไม่เกิดปัญหา

class Bird(ABC):
    @abstractmethod
    def move(self): pass

class FlyingBird(Bird):
    def move(self):
        return "Flying"

class SwimmingBird(Bird):
    def move(self):
        return "Swimming"

# === I — Interface Segregation Principle ===
# แยก interface ให้เล็กและเฉพาะเจาะจง

class Printable(ABC):
    @abstractmethod
    def print_document(self): pass

class Scannable(ABC):
    @abstractmethod
    def scan_document(self): pass

class Faxable(ABC):
    @abstractmethod
    def fax_document(self): pass

class ModernPrinter(Printable, Scannable):
    def print_document(self): return "Printing"
    def scan_document(self): return "Scanning"

class BasicPrinter(Printable):
    def print_document(self): return "Printing"

# === D — Dependency Inversion Principle ===
# ขึ้นอยู่กับ abstraction ไม่ใช่ implementation

class Database(ABC):
    @abstractmethod
    def query(self, sql: str): pass

class PostgreSQL(Database):
    def query(self, sql: str):
        return f"PostgreSQL: {sql}"

class MySQL(Database):
    def query(self, sql: str):
        return f"MySQL: {sql}"

class UserService:
    def __init__(self, db: Database):  # ขึ้นอยู่กับ abstraction
        self.db = db
    
    def get_user(self, user_id: str):
        return self.db.query(f"SELECT * FROM users WHERE id='{user_id}'")

# เปลี่ยน database ได้ง่าย
service_pg = UserService(PostgreSQL())
service_mysql = UserService(MySQL())

Design Patterns ที่ใช้บ่อยใน OOP

ตัวอย่าง Design Patterns ที่ใช้บ่อยในการพัฒนาซอฟต์แวร์

#!/usr/bin/env python3
# design_patterns.py — Common Design Patterns

# === Singleton Pattern ===
class DatabaseConnection:
    _instance = None
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance.connection = "Connected to DB"
        return cls._instance

db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2)  # True

# === Factory Pattern ===
class NotificationFactory:
    @staticmethod
    def create(channel: str, **kwargs):
        if channel == "email":
            return EmailNotification(**kwargs)
        elif channel == "sms":
            return SMSNotification(**kwargs)
        elif channel == "push":
            return PushNotification(**kwargs)
        raise ValueError(f"Unknown channel: {channel}")

class EmailNotification:
    def __init__(self, to, subject="", body=""):
        self.to = to
        self.subject = subject
        self.body = body
    def send(self):
        return f"Email sent to {self.to}"

class SMSNotification:
    def __init__(self, phone, message=""):
        self.phone = phone
        self.message = message
    def send(self):
        return f"SMS sent to {self.phone}"

class PushNotification:
    def __init__(self, device_token, title="", body=""):
        self.device_token = device_token
    def send(self):
        return f"Push sent to {self.device_token[:8]}..."

# === Observer Pattern ===
class EventEmitter:
    def __init__(self):
        self._listeners = {}
    
    def on(self, event: str, callback):
        if event not in self._listeners:
            self._listeners[event] = []
        self._listeners[event].append(callback)
    
    def emit(self, event: str, *args, **kwargs):
        for callback in self._listeners.get(event, []):
            callback(*args, **kwargs)

class OrderSystem(EventEmitter):
    def place_order(self, order_id, items, total):
        # Process order
        self.emit("order_placed", order_id=order_id, total=total)
    
    def cancel_order(self, order_id):
        self.emit("order_cancelled", order_id=order_id)

# Usage
orders = OrderSystem()
orders.on("order_placed", lambda **kw: print(f"Email: Order {kw['order_id']} confirmed"))
orders.on("order_placed", lambda **kw: print(f"Inventory: Reduce stock for {kw['order_id']}"))
orders.on("order_cancelled", lambda **kw: print(f"Refund: Process refund for {kw['order_id']}"))
orders.place_order("ORD-001", ["laptop"], 59900)

# === Strategy Pattern ===
class SortStrategy(ABC):
    @abstractmethod
    def sort(self, data: list) -> list:
        pass

class QuickSort(SortStrategy):
    def sort(self, data: list) -> list:
        if len(data) <= 1: return data
        pivot = data[len(data) // 2]
        left = [x for x in data if x < pivot]
        middle = [x for x in data if x == pivot]
        right = [x for x in data if x > pivot]
        return self.sort(left) + middle + self.sort(right)

class BubbleSort(SortStrategy):
    def sort(self, data: list) -> list:
        arr = data.copy()
        for i in range(len(arr)):
            for j in range(len(arr) - i - 1):
                if arr[j] > arr[j+1]:
                    arr[j], arr[j+1] = arr[j+1], arr[j]
        return arr

class Sorter:
    def __init__(self, strategy: SortStrategy):
        self.strategy = strategy
    def sort(self, data):
        return self.strategy.sort(data)

FAQ คำถามที่พบบ่อย

Q: OOP กับ Functional Programming ต่างกันอย่างไร?

A: OOP จัดโครงสร้างโค้ดเป็น objects ที่รวม data และ behavior เน้น mutable state และ side effects ที่ควบคุมผ่าน encapsulation ส่วน FP เน้น pure functions ที่ไม่เปลี่ยน state ใช้ immutable data และ function composition ภาษาสมัยใหม่เช่น Python, TypeScript, Kotlin รองรับทั้งสองแนวทาง เลือกใช้ตามความเหมาะสมของปัญหา

Q: Composition over Inheritance หมายความว่าอย่างไร?

A: หมายความว่าควรใช้ composition (มี object เป็น property) แทน inheritance (สืบทอดจาก class) เมื่อทำได้ เพราะ inheritance สร้าง tight coupling ระหว่าง parent-child classes ถ้า parent เปลี่ยน child ได้รับผลกระทบ ส่วน composition ยืดหยุ่นกว่า เปลี่ยน component ได้ง่าย Go ภาษาตัดสินใจไม่มี inheritance เลย ใช้ composition อย่างเดียว

Q: Abstract Class กับ Interface ต่างกันอย่างไร?

A: Abstract class สามารถมีทั้ง abstract methods และ concrete methods (methods ที่มี implementation) และมี instance variables ได้ ส่วน Interface (ใน Java/TypeScript) มีแค่ method signatures ไม่มี implementation class สามารถ implement หลาย interfaces ได้แต่ inherit ได้แค่ abstract class เดียว (ยกเว้น Python ที่รองรับ multiple inheritance)

Q: เมื่อไหร่ไม่ควรใช้ OOP?

A: ไม่ควรใช้ OOP เมื่อโปรเจกต์เล็กมากเช่น scripts ไม่กี่บรรทัด เมื่อปัญหาเป็น data transformation pipeline ที่ FP เหมาะกว่า เมื่อ performance เป็นสิ่งสำคัญมากเช่น embedded systems หรือ game engines ที่ OOP overhead อาจเป็นปัญหา และเมื่อทีมไม่คุ้นเคยกับ OOP ควรเรียนรู้ก่อนนำไปใช้กับโปรเจกต์จริง

Q: Python รองรับ private variables จริงหรือ?

A: Python ไม่มี true private เหมือน Java แต่ใช้ name mangling ด้วย double underscore (เช่น __balance จะกลายเป็น _ClassName__balance) ทำให้เข้าถึงจากภายนอกยากขึ้น single underscore (เช่น _balance) เป็นแค่ convention บอกว่าเป็น protected แต่ยังเข้าถึงได้ Python เชื่อในหลัก "we are all consenting adults"

📖 บทความที่เกี่ยวข้อง

abstract ใน oop คืออ่านบทความ → smart money concepts advancedอ่านบทความ → smart money concepts youtubeอ่านบทความ → smart money concepts courseอ่านบทความ → smart money concepts forexอ่านบทความ →

📚 ดูบทความทั้งหมด →