Dependency injection
Bài đăng này đã không được cập nhật trong 7 năm
Bài viết này bàn về kĩ thuật Dependency Injection, có nhiều thuật ngữ trừu tượng và khá phức tạp. Trước khi đọc bài viết này, bạn nên tìm hiểu một số principle sau trong thiết kế phần mềm:
- IoC, Inversion of control (hiểu nôm na là kĩ thuật đảo ngược) https://en.wikipedia.org/wiki/Inversion_of_control
- Loose_coupling, xem thêm https://en.wikipedia.org/wiki/Loose_coupling)
Dependency Injection đã phát triển 5 năm. Tư tưởng depency injection có thể thấy từ ví dụ sau:
Khi bạn đi và lấy một số thứ từ trong tủ lạnh cho chính mình, bạn có thể gặp vấn đề. Bạn có thể để cửa mở, có thể có một vài thứ mà bố mẹ bạn không muốn bạn có. Thậm chí, bạn có thể đang tìm kiếm cái mà trong tủ không có hoặc đã hết hạn. Tất cả những gì bạn cần làm là đưa ra nhu cầu của mình: Chẳng hạn, Tôi cần vài thứ cho bữa trưa. Dependency Injection đóng vai trò đáp ứng nhu cầu đấy, ở đây là chắc chắn nó sẽ có vài thứ cho bữa trưa của bạn. (John Munsch, 28 October 2009)
Trong kĩ thuật phầm mềm, Dependency injection là một công nghệ mà theo đó một object cung cấp sự phụ thuộc cho một object khác.
- Dependency là một object có thể được sử dụng (xem nó như 1 service).
- Injection là việc chuyển Dependency vào object client ( object sẽ sử dụng service). Việc injection service đến client thay vì để client tìm và gọi service là nền tảng cơ bản của pattern Dependency injection.
Có vẻ hơi khó hiểu. Yêu cầu cơ bản này có nghĩa việc sử dụng các giá trị của services được tạo ra từ new
hoặc static
đều bị cấm. Mục đích của Dependency injection là tách các objects ra khỏi client, khi mà thay đổi hành vi hay định nghĩa của object này cũng không làm thay đổi dòng code nào của client.
Dependency injection là một dạng của kỹ thuật inversion of control (IoC) . Bạn nào chưa đọc qua IoC thì nên tìm hiểu link này trước https://en.wikipedia.org/wiki/Inversion_of_control . Thay vì code cấp thấp gọi đến code cấp cao, code cấp cao có thể nhận được code cấp thấp hơn mà nó có thể gọi đến. Điều này đảo ngược mô hình kiểm soát điển hình được thấy trong lập trình thủ tục. Ví dụ IoC:
public class ServerFacade {
public <K, V> V respondToRequest(K request, DAO dao) {
return new DataAccessObject().getData(request);
}
}
Khi đối tượng cấp thấp DAO (DataAccessObject) getData hoàn thành thì ServerFacade sẽ nhận được lệnh xử lý tiếp theo.
Giống như các IoC khác, Depency Injection hỗ trợ các nguyên tắc Inversion (dịch tiếng Việt là nguyên tắc đảo ngược, nhưng tôi để Inversion, sẽ dễ và clear hơn). Client sẽ định nghĩa các phương thức, interface, cho phép mã bên ngoài khác truy cập. Client không được phép gọi inject code. Inject code để khởi tạo service và inject client vào service đó.
Điều này có nghĩa client code không quan tâm về inject code, cũng không cần quan tâm đến service được tạo ra thế nào, chạy ra sao và làm gì. Client chỉ cần thực thi nhiệm vụ của nó một cách trọn vẹn, xác định service sẽ dùng gì của client và dùng nó như thế nào.
Việc này tách biệt trách nhiệm của phần sử dụng và phần xây dựng.
Overview
Dependency injection chia tách việc tạo ra một tập các phụ thuộc của client từ các hành vi của clients, việc này cho phép thiết kế chương trình trở nên ghép nối lỏng lẻo (Loose_coupling, xem thêm https://en.wikipedia.org/wiki/Loose_coupling) và tuân theo IoC. Nó tương phản trực tiếp với mô hình service locator (cho phép client biết về hệ thống sử dụng nó).
Việc injection , cơ bản không phải là một cơ chế mới hay cơ chế tuỳ chỉnh nào. Nó hoạt động theo cùng một cách với việc passing các tham số. Tham chiếu đến tham số cũng có nghĩa là nó đang được thực hiện để cô lập client vs chi tiết. Một Injection tương tự như việc kiểm soát để passing parameter, và nó độc lập với việc làm thế nào để passing parameter cho dù truyền bằng tham chiếu hay tham trị.
Dependency Injection gồm 4 vai trò:
- Services: những đối tượng được sử dụng ( bởi clients)
- Clients: Những đối tượng phụ thuộc services, sử dụng dụng services
- Interfaces: Giao diện định nghĩa cách mà client sẽ sử dụng services
- Injector: có trách nhiệm xây dựng các services và inject service vào trong clients
Bất kì đối tượng nào được sử dụng cũng được gọi là services, đối tượng nào dùng services cũng có thể được gọi là client. Client nên không có kiến thức cụ thể về việc thực hiện của server. Nó chỉ nên biết tên của giao diện và API. Kết quả là, client sẽ không cần phải thay đổi ngay cả khi những gì là đằng sau interface thay đổi. Tuy nhiên, nếu tầng interface được tái cấu trúc từ class sang interface (hoặc ngược lại), client sẽ cần phải biên dịch lại. Điều này rất quan trọng nếu client và server được xuất bản riêng. Sự ghép nối không may này là injection không thể giải quyết được.
Taxonomy
IoC tổng quát hơn DIP (Dependency inversion principle ( https://en.wikipedia.org/wiki/Dependency_inversion_principle )). Nói một cách đơn giản, IoC có nghĩa là để cho các mã khác gọi bạn chứ không phải nhấn mạnh vào việc bạn gọi cái gì.
Advanced
- Dependency injection cho phép client linh hoạt trong việc thay đổi cấu hình. Khi thay đổi hành vi client, chỉ cần client fix. Client có thể có bất kì hành động nào miễn dựa trên những interface mà services mong muốn.
- DJ thuận tiện trong việc sử dụng lại. Các đối tượng client độc lập với service nên chúng có thể được sử dụng lại cực dễ dàng ngay cả trong hệ thống khác.
- Dễ kiểm thử và bảo trì. Việc phát triển độc lập mã client giúp kiểm thử và bảo trì mã này dễ hơn. Phát hiện lỗi cũng dễ hơn do phạm vi thu hẹp lại
Disadvanced
- Injection có thể làm cho mã khó theo dõi (đọc) vì nó ngăn cách hành vi từ contructor. Điều này có nghĩa là các nhà phát triển phải tham khảo nhiều tệp hơn để theo dõi cách hệ thống thực hiện.
- Việc tiêm phụ thuộc thường đòi hỏi phải có nhiều nỗ lực phát triển trước vì người ta không thể triệu tập vào điều gì đó đúng khi nào và ở đâu là cần thiết nhưng phải yêu cầu tiêm chích và sau đó đảm bảo rằng nó đã được inject.
- Áp lực phụ thuộc vào sự phức tạp để tách mã ra khỏi class và vào mối liên kết giữa các class có thể không phải lúc nào cũng dễ quản lý
Link Reference
All rights reserved