Dependency Inversion Principle
High-level modules should not import anything from low-level modules. Both should depend on abstractions (e.g., interfaces). Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions.
High-level modules ไม่ควรที่จะ import low-level modules มาใช้ตรงๆ หากต้องการจะใช้ ควรจะให้มันยู่ที่ Protocal แทน
❌ Bad
อย่างเช่นผมมี class MessagingApp
แล้วผมอยากเรียกใช้ EmailService
ไว้ใน class MessagingApp
ด้วย เราไม่ควรที่จะสร้าง Object ไว้ใน class ตรงๆ
// Low-level module (Concrete implementation)
class EmailService {
func sendEmail(message: String, to: String) {
print("Email sent to \(to): \(message)")
}
}
// High-level module (Depends on low-level module directly)
class MessagingApp {
private let emailService = EmailService()
func sendMessage(message: String, to: String) {
emailService.sendEmail(message: message, to: to)
}
}
let messagingApp = MessagingApp()
messagingApp.sendMessage(message: "Hello", to: "[email protected]")
// Output: Email sent to [email protected]: Hello
✅ Good
แต่เราควรใช้วิธีการ initialize แทน นอกจากจะทำให้ code ดูเป็นสัดเป็นส่วนแล้ว ยังง่ายต่อการ Test อีกด้วย เพราะจะมองออกทันที ว่าอะไรเป็นอะไร
// Abstraction (Protocol)
protocol MessageService {
func sendMessage(message: String, to: String)
}
// Low-level module (Concrete implementation)
class EmailService: MessageService {
func sendMessage(message: String, to: String) {
print("Email sent to \(to): \(message)")
}
}
// High-level module (Depends on abstraction)
class MessagingApp {
private let messageService: MessageService
init(messageService: MessageService) {
self.messageService = messageService
}
func sendMessage(message: String, to: String) {
messageService.sendMessage(message: message, to: to)
}
}
// Using Dependency Inversion Principle
let emailService = EmailService()
let messagingApp = MessagingApp(messageService: emailService)
messagingApp.sendMessage(message: "Hello", to: "[email protected]")
// Output: Email sent to [email protected]: Hello