Rails 5.1 เพิ่ม delegate_missing_to ให้ Forward Method ที่ไม่มีไป Object อื่น แทนที่จะสร้าง Subclass บทความนี้วิเคราะห์ว่าทำไม Decorator Pattern ถึงดีกว่า Inheritance บางกรณี
delegate_missing_to คืออะไร?
class Player
delegate_missing_to :@user
def initialize(user)
@user = user
end
def points
Game.points_for_user(user.id)
end
end
Player.new(user).name # เรียก user.name ผ่าน delegate_missing_to
Gavin คอมเมนต์ว่า: "ทำไมไม่สร้าง Subclass แทน? ได้ผลเหมือนกัน ไม่ต้องเพิ่ม Feature" → DHH ใน Pull Request อธิบายว่า: "นี่คือ Pattern ปกติสำหรับ Decorator"
ทำไมต้อง Decorator?
Decorator เปลี่ยนพฤติกรรม Object โดยไม่สร้าง Subclass
Player "Decorate" User → Player เกือบเหมือน User แต่มี Method เพิ่ม points ทำได้โดยไม่ใช้ Inheritance
เมื่อไหร่ควรใช้ Decorator?
กรณีที่ 1: สร้าง Object ครั้งเดียว ใช้เลย (Subclass ดีกว่า)
# Decorator - โค้ดมากกว่า
player = Player.new(User.new(name: "Justin"))
# Subclass - สั้นกว่า
player = Player.new(name: "Justin")
✅ ถ้าสร้างและใช้ในที่เดียว Subclass ดีกว่า Decorator แค่ซับซ้อน
กรณีที่ 2: เพิ่มพฤติกรรมภายหลัง ไกลจากจุดสร้าง (Decorator ดีกว่า)
user = User.find(1)
# ... โค้ดอื่นๆ ระยะไกล ...
player = Player.new(user)
✅ Decorator ช่วย Separate Behavior:
- Code สร้าง User ไม่ต้องรู้ว่า Player มีอยู่
- ยังใช้ User Object ตัวเดิมได้ ถ้าไม่ต้องการ Method เพิ่ม
- แยก Behavior: Player, Employee, Developer แต่ละ Class ทำหน้าที่เดียว (Single Responsibility)
กรณีที่ 3: หลีกเลี่ยง Private Method Coupling
Subclass เรียก Private Method ของ Parent ได้ → แตกง่ายตอน Parent เปลี่ยน Implementation
Decorator เรียกได้แค่ Public Interface → Decoupled จาก Implementation Details
รวม Decorators ได้ (Composition)
# Player decorates User
# Admin decorates Player
# Auditor decorates Admin
player = Player.new(user)
admin = Admin.new(player)
auditor = Auditor.new(admin)
auditor.name # → user.name (Delegate chain)
auditor.points # → player.points
auditor.permissions # → admin.permissions
✅ แต่ละ Decorator ทำหน้าที่เดียว รวมกันได้ Complex Behavior
Ruby มีหลายวิธี Share Behavior
- Subclass (Inheritance)
- Modules (Mixin)
- Delegate / Forwardable
- Method Missing / SimpleDelegator
- Decorator Pattern - ใช้ Instance Variable + Method Call (Building Blocks ของ OOP)
Decorator ให้ Flexible Behavior ระหว่าง Runtime โดยไม่ Overcomplicate Code
สรุป
| สถานการณ์ | แนะนำ |
|---|---|
| Behavior คงที่ สร้างใช้ทันที | Subclass / Module Include |
| เพิ่ม Behavior ภายหลัง / Dynamic | Decorator |
| ต้องการแยก Responsibilities | Decorator |
| อยากหลีกเลี่ยง Parent Private Method Coupling | Decorator |
| ต้อง Compose Multiple Behaviors | Decorator Chain |