ai
Composition OOP คือ — หลักการ Composition over
Composition OOP

Composition OOP Has-a Relationship Composition over Inheritance Dependency Injection Design Patterns Loose Coupling Flexibility Runtime Behavior Strategy Decorator
เนื้อหาเกี่ยวข้อง — แนะนำให้อ่าน Svelte 5 Runes High Availability HA Setup
| Concept | Relationship | Coupling | Flexibility | เหมาะกับ |
|---|---|---|---|---|
| Inheritance | Is-a | Tight | ต่ำ | True Hierarchy |
| Composition | Has-a | Loose | สูง | ทั่วไป |
| Aggregation | Has-a (weak) | Loose | สูง | Optional Parts |
| Interface | Can-do | Very Loose | สูงมาก | Contract |
| Mixin | Mixed-in | ปานกลาง | ปานกลาง | Shared Behavior |
Composition vs Inheritance
# === Composition vs Inheritance ===
# BAD: Deep Inheritance Hierarchy
# class Animal:
# def eat(self): ...
#
# class Mammal(Animal):
# def breathe(self): ...
#
# class Dog(Mammal):
# def bark(self): ...
#
# class GuideDog(Dog):
# def guide(self): ...
#
# Problem: GuideDog สืบทอด 4 ชั้น เปลี่ยน Animal กระทบทุก Class
# GOOD: Composition
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Protocol
# Define Behaviors as Protocols (Interfaces)
class Movable(Protocol):
def move(self) -> str: ...
class Soundable(Protocol):
def make_sound(self) -> str: ...
class Trainable(Protocol):
def perform_task(self, task: str) -> str: ...
# Implement Behaviors as separate classes
class WalkBehavior:
def move(self) -> str:
return "Walking on 4 legs"
class FlyBehavior:
def move(self) -> str:
return "Flying with wings"
class SwimBehavior:
def move(self) -> str:
return "Swimming with fins"
class BarkSound:
def make_sound(self) -> str:
return "Woof!"
class MeowSound:
def make_sound(self) -> str:
return "Meow!"
class GuideTraining:
def perform_task(self, task: str) -> str:
return f"Guiding: {task}"
class SearchTraining:
def perform_task(self, task: str) -> str:
return f"Searching for: {task}"
# Compose behaviors into Animal
@dataclass
class Animal:
name: str
movement: Movable
sound: Soundable
training: Trainable = None
def describe(self):
desc = f"{self.name}: {self.movement.move()} | {self.sound.make_sound()}"
if self.training:
desc += f" | Can: {self.training.perform_task('demo')}"
return desc
# Create animals with different compositions
dog = Animal("Dog", WalkBehavior(), BarkSound())
guide_dog = Animal("Guide Dog", WalkBehavior(), BarkSound(), GuideTraining())
search_dog = Animal("Search Dog", WalkBehavior(), BarkSound(), SearchTraining())
cat = Animal("Cat", WalkBehavior(), MeowSound())
animals = [dog, guide_dog, search_dog, cat]
print("=== Composition Example ===")
for a in animals:
print(f" {a.describe()}")
# Runtime behavior change!
print("\n Dog learns to swim:")
dog.movement = SwimBehavior()
print(f" {dog.describe()}")
Design Patterns

# === Strategy Pattern (Composition) ===
class PaymentStrategy(Protocol):
def pay(self, amount: float) -> str: ...
class CreditCardPayment:
def __init__(self, card_number: str):
self.card = card_number[-4:]
def pay(self, amount: float) -> str:
return f"Paid with Credit Card ****{self.card}"
class PayPalPayment:
def __init__(self, email: str):
self.email = email
def pay(self, amount: float) -> str:
return f"Paid via PayPal ({self.email})"
class CryptoPayment:
def __init__(self, wallet: str):
self.wallet = wallet[:8]
def pay(self, amount: float) -> str:
return f"Paid with Crypto ({self.wallet}...)"
@dataclass
class ShoppingCart:
items: list = field(default_factory=list)
payment: PaymentStrategy = None
def add_item(self, name: str, price: float):
self.items.append({"name": name, "price": price})
def total(self) -> float:
return sum(item["price"] for item in self.items)
def checkout(self) -> str:
if not self.payment:
return "Error: No payment method set"
return self.payment.pay(self.total())
cart = ShoppingCart()
cart.add_item("Laptop", 999.99)
cart.add_item("Mouse", 29.99)
# Strategy: เปลี่ยน Payment Method ตอน Runtime
cart.payment = CreditCardPayment("4111111111111234")
print(f"\n=== Strategy Pattern ===")
print(f" {cart.checkout()}")
cart.payment = PayPalPayment("user@example.com")
print(f" {cart.checkout()}")
cart.payment = CryptoPayment("0x1234567890abcdef")
print(f" {cart.checkout()}")
# === Decorator Pattern (Composition) ===
class Logger:
def __init__(self, wrapped):
self._wrapped = wrapped
def pay(self, amount: float) -> str:
print(f" [LOG] Processing payment of ")
result = self._wrapped.pay(amount)
print(f" [LOG] Payment result: {result}")
return result
print(f"\n=== Decorator Pattern ===")
logged_payment = Logger(CreditCardPayment("9876543210001234"))
logged_payment.pay(1029.98)
Dependency Injection
# === Dependency Injection with Composition ===
# Database Repository (Interface)
class UserRepository(Protocol):
def find_by_id(self, user_id: int) -> dict: ...
def save(self, user: dict) -> bool: ...
# Concrete Implementations
class PostgresUserRepo:
def find_by_id(self, user_id: int) -> dict:
return {"id": user_id, "name": "John", "source": "PostgreSQL"}
def save(self, user: dict) -> bool:
return True
class MongoUserRepo:
def find_by_id(self, user_id: int) -> dict:
return {"id": user_id, "name": "John", "source": "MongoDB"}
def save(self, user: dict) -> bool:
return True
class InMemoryUserRepo:
"""For testing"""
def __init__(self):
self.users = {}
def find_by_id(self, user_id: int) -> dict:
return self.users.get(user_id, {})
def save(self, user: dict) -> bool:
self.users[user["id"]] = user
return True
# Service uses Composition + DI
@dataclass
class UserService:
repo: UserRepository # Injected dependency
def get_user(self, user_id: int) -> dict:
return self.repo.find_by_id(user_id)
def update_user(self, user_id: int, name: str) -> bool:
user = self.repo.find_by_id(user_id)
user["name"] = name
return self.repo.save(user)
# Production: ใช้ Postgres
prod_service = UserService(repo=PostgresUserRepo())
print(f"\n=== Dependency Injection ===")
print(f" Production: {prod_service.get_user(1)}")
# Testing: ใช้ InMemory
test_repo = InMemoryUserRepo()
test_repo.save({"id": 1, "name": "Test User"})
test_service = UserService(repo=test_repo)
print(f" Testing: {test_service.get_user(1)}")
# Switch to Mongo: เปลี่ยน Implementation ไม่ต้องแก้ Service
mongo_service = UserService(repo=MongoUserRepo())
print(f" MongoDB: {mongo_service.get_user(1)}")
# Benefits Summary
benefits = {
"Loose Coupling": "Service ไม่ผูกกับ Database ใดๆ",
"Testability": "Mock/InMemory Repository สำหรับ Test",
"Flexibility": "เปลี่ยน Database ไม่ต้องแก้ Business Logic",
"Single Responsibility": "แต่ละ Class ทำหน้าที่เดียว",
"Open/Closed": "เพิ่ม Implementation ใหม่ไม่ต้องแก้ Code เดิม",
}
print(f"\n Composition Benefits:")
for k, v in benefits.items():
print(f" [{k}]: {v}")
เคล็ดลับ
- Favor Composition: เลือก Composition ก่อน ใช้ Inheritance เมื่อจำเป็นจริงๆ
- Protocol: ใช้ Protocol/Interface กำหนด Contract
- DI: Inject Dependencies ผ่าน Constructor
- Small Classes: สร้าง Class เล็กๆ ทำหน้าที่เดียว แล้วรวมกัน
- Test: Composition ทำให้ Mock ง่าย Test ง่าย
Composition ใน OOP คืออะไร
สร้าง Object รวม Object อื่น Has-a Relationship แทน Inheritance ยืดหยุ่น เปลี่ยน Runtime Loose Coupling Test ง่าย Mock ง่าย
แนะนำเพิ่มเติม — XM Signal
เนื้อหาเกี่ยวข้อง — ดูเพิ่มเติมเรื่อง Prometheus PromQL Observability Stack
เนื้อหาเกี่ยวข้อง — ดูเพิ่มเติมเรื่อง Prometheus PromQL DevOps Culture





