I. Định Nghĩa
Dependency Injection là kỹ thuật giúp giảm sự phụ thuộc giữa các module code bằng cách "tiêm" các dependencies (các đối tượng hoặc dữ liệu mà một đối tượng cần để thực hiện công việc của nó) thay vì để đối tượng tự tạo ra chúng. Trong ngôn ngữ Go, điều này thường được thực hiện thông qua interfaces. Một đối tượng chỉ cần định nghĩa những gì nó cần (thông qua một interface) và các đối tượng khác có thể cung cấp những gì nó cần nếu chúng tuân thủ interface đó.
II. Ví dụ
Trong ví dụ này chúng ta sẽ tạo ra một dịch vụ gửi tin nhắn qua Email và SMS.
Đầu tiên, chúng ta định nghĩa một interface MessageService
với một phương thức SendMessage
. Interface này không cung cấp chi tiết về việc làm thế nào để gửi tin nhắn, chỉ đơn giản là yêu cầu một "dịch vụ tin nhắn" phải có khả năng gửi tin nhắn.
// MessageService handles some message type MessageService interface { SendMessage(message string, receiver string) error }
Tiếp theo, chúng ta định nghĩa hai struct SMSService
và EmailService
, cả hai đều implement MessageService
interface. Điều này có nghĩa là cả hai đều cung cấp phương thức SendMessage
, nhưng cách thực hiện của mỗi dịch vụ có thể khác nhau.
// SMSService is a implementation of MessageService type SMSService struct{} func (s *SMSService) SendMessage(message string, receiver string) error { fmt.Printf("Send SMS: %s to %s\n", message, receiver) return nil } // EmailService is another implementation of MessageService type EmailService struct{} func (e *EmailService) SendMessage(message string, receiver string) error { fmt.Printf("Send Email: %s to %s\n", message, receiver) return nil }
Tiếp theo tạo MyApplication
struct có một trường messageService
kiểu MessageService
.
// MyApplication uses a service to send messages
type MyApplication struct { messageService MessageService
} func (a *MyApplication) processMessages(message string, receiver string) error { err := a.messageService.SendMessage(message, receiver) if err != nil { return err } return nil
}
Điều này có nghĩa là MyApplication
không cần biết chi tiết về việc làm thế nào để gửi tin nhắn, chỉ cần biết rằng nó có một dịch vụ có thể gửi tin nhắn. Đây chính là Dependency Injection (DI): MyApplication
không tạo ra một MessageService
, thay vào đó, nó được cung cấp một MessageService
khi được tạo.
Trong hàm main, chúng ta tạo ra một SMSService
và EmailService
, và "tiêm" chúng vào MyApplication
thông qua trường messageService
.
func main() { smsService := &SMSService{} app := &MyApplication{messageService: smsService} app.processMessages("Hello World", "123") emailService := &EmailService{} app.messageService = emailService app.processMessages("Hello World", "abc@example.com")
}
Trong ví dụ trên, MyApplication
không cần biết rằng nó đang sử dụng SMSService
hay EmailService
để gửi tin nhắn. Nó chỉ cần biết rằng nó có một dịch vụ để gửi tin nhắn. Điều này giúp giảm sự phụ thuộc giữa các module và giúp chúng ta dễ dàng thay đổi hoặc thử nghiệm với các dịch vụ khác nhau.