Dependency Inversion Principle (DIP) เป็นหลักการหนึ่งใน SOLID Principles:
1. High-level modules ไม่ควรพึ่งพา Low-level modules ทั้งคู่ควรพึ่งพา Abstractions
2. Abstractions ไม่ควรพึ่งพา Details Details ควรพึ่งพา Abstractions
เป้าหมาย: ลด Coupling ระหว่างโมดูล ทำให้เปลี่ยน Implementation ได้ง่าย
ตัวอย่าง: ก่อนใช้ DIP (Violation)
// Low-level modules
public class Email
{
public string To { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
public void Send() { /* Send email logic */ }
}
public class SMS
{
public string PhoneNumber { get; set; }
public string Message { get; set; }
public void Send() { /* Send SMS logic */ }
}
// High-level module พึ่งพา Concrete Classes โดยตรง
public class Notification
{
private readonly Email _email = new Email(); // ทำให้ติดกับ Email
private readonly SMS _sms = new SMS(); // ทำให้ติดกับ SMS
public void Send()
{
_email.Send();
_sms.Send();
}
}
ปัญหา: Notification ติดกับ Email และ SMS โดยตรง (Tight Coupling) หากเพิ่ม Push Notification ต้องแก้ Notification
ตัวอย่าง: หลังใช้ DIP (Compliant)
// 1. Abstraction (Interface)
public interface IMessage
{
void Send();
}
// 2. Low-level Modules Implement Abstraction
public class Email : IMessage
{
public string To { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
public void Send() { /* Send email */ }
}
public class SMS : IMessage
{
public string PhoneNumber { get; set; }
public string Message { get; set; }
public void Send() { /* Send SMS */ }
}
// 3. เพิ่มใหม่ได้ง่าย ไม่ต้องแก้โค้ดเดิม
public class PushNotification : IMessage
{
public string DeviceToken { get; set; }
public string Payload { get; set; }
public void Send() { /* Send Push */ }
}
// 4. High-level Module พึ่งพา Abstraction (IMessage)
public class Notification
{
private readonly IEnumerable<IMessage> _messages;
// รับ Dependency ผ่าน Constructor (Constructor Injection)
public Notification(IEnumerable<IMessage> messages)
{
_messages = messages;
}
public void Send()
{
foreach (var msg in _messages)
{
msg.Send(); // Polymorphism
}
}
}
การลงทะเบียนใน DI Container (ASP.NET Core)
services.AddTransient<IMessage, Email>();
services.AddTransient<IMessage, SMS>();
services.AddTransient<IMessage, PushNotification>();
services.AddTransient<Notification>(); // จะได้ IEnumerable<IMessage> อัตโนมัติ
ประโยชน์
- High-level Module (Notification) ไม่รู้จัก Low-level Details (Email, SMS)
- เพิ่ม/ลด/เปลี่ยน Channel ได้โดยไม่แก้ Notification
- ทดสอบง่าย (Mock IMessage)
- รองรับ Open/Closed Principle
สรุป
DIP = Programming to Interfaces, not Implementations ใช้ Constructor Injection + DI Container จะได้ DIP อย่างแท้จริง