Dependency Injection (DI) là gì? Minh họa qua lập trình java

Trong bài viết này tôi sẽ giúp các bạn hiểu rõ về Dependency Injection và cũng như ưu nhược điểm khi sử dụng trong lập trình java.

 

1. Dependency Injection là gì?

Dependency Injection là 1 kỹ thuật, 1 design pattern cho phép xóa bỏ sự phụ thuộc hard-code và làm cho ứng dụng của bạn dễ mở rộng và maintain hơn.

Để hiểu định nghĩa trên, mình có ví dụ sau:

Tôi có 1 ứng dụng gọi tới đối tượng của lớp MySqlDao(class MySqlDao để kết nối và làm việc với cơ sở dữ liệu MySQL của ứng dụng)

Bây giờ bạn muốn truy vấn tới cơ sở dữ liệu SQL Server. Bạn phải xóa khai báo MySqlDao trong ứng dụng và thay bằng SqlServerDao. Sau đó muốn dùng lại MySqlDao bạn lại làm ngược lại… rõ ràng code sẽ phải sửa lại và kiểm tra lại nhiều lần.

Giải pháp dùng if-else kiểm tra điều kiện sẽ dùng đối tượng DAO nào. Nhưng sau đấy có thêm một DAO khác ví dụ như OracleDao chẳng hạn… phức tạp hơn nhiều phải không.

(Thường thì ít khi 1 ứng dụng dùng nhiều loại cơ sở dữ liệu khác nhau nhưng sẽ có trường hợp sử dụng nhiều database, chúng ta để thành nhiều loại cơ sở dữ liệu khác nhau cho dễ hình dung)

Dependency Injection chính là để giải quyết cho trường hợp như thế này.

Trong ví dụ trên ta tạo 1 interface AbstractDao và cho các lớp DAO kia thừa kế AbstractDao trong lập trình java. Bây giờ trong các lớp sử dụng DAO ta khai báo AbstractDAO. Tùy theo điều kiện tương ứng AbstractDao có thể là MySqlDao hoặc SqlServerDao.

Việc thay thế AbstractDAO bằng MySqlDao/SqlServerDao được gọi là injection.

2. Minh họa qua lập trình java.

Để các bạn lập trình java hiểu rõ hơn về khái niệm Depedency Injection chúng ta sẽ tạo một interface để khai báo các method giao tiếp với cơ sở dữ liệu:

Interface trên mục đích khai báo những phương thức mình sẽ sử dụng và bắt buộc lớp cài đặt phải sử dụng nó trong dự án. Sau đó thực hiện tạo các lớp MySqlDao và SqlServer lần như sau:

Lớp SqlServerDao trong java như sau:

Lớp OracleDao trong java như sau:

Trong đó file config.properites lưu thông tin config quyết định sẽ kết nối tới database nào.

Bây giờ ở lớp cần dùng đến DAO ta sẽ khai báo AbstractDao trong java. Tùy theo tham số trong file config mà ta khởi tạo đối tượng AbstractDao là MySqlDao, SqlServerDao hay OracleDao.

Như các bạn thấy ở đây tôi dùng Factory Pattern để quyết định đối tượng được tạo ra. Trong đó FactoryDao (Factory class) sẽ đọc file và quyết định đối tượng nào được tạo ra.

Thực hiện chạy ví dụ trên:

Kết quả:

Thực hiện sửa lại giá trị thuộc tính database = 3 trong file cấu hình sau đó chạy lại:

Bây giờ nếu bạn có thêm 1 loại database khác cần sử dụng thì chỉ cần tạo DAO cho nó. Bạn chỉ cần cài đặt (implements) dựa trên giao diện AbstractDao và sửa lại FactoryDao là được.

Ví dụ mình có thêm database DB2. Tôi sẽ tạo class DB2Dao.java implements AbstractDao.

trong method getDao() của FactoryDao thêm điều kiện nếu database = 4 thì sẽ trả về DB2Dao. Rõ ràng cách làm này giúp ta sẽ mở rộng ứng dụng hơn rất nhiều và mỗi lần thay đổi đối tượng DAO ta không cần phải khởi động (deploy) lại ứng dụng mà chỉ cần thay đổi thông tin trong file config.properties.

Việc lấy thông tin từ file config.properites rồi quyết định tạo đối tượng trong class DataProvider.java chính là tiêm sự phụ thuộc (Dependency Injection – DI)

3. Các phương pháp thực hiện Dependency Injection.

Các phương pháp cơ bản để Dependency Injection.

  • Constructor Injection: Các dependency sẽ được truyền vào (inject vào) 1 class thông qua constructor của lớp đó. Đây là cách thông dụng nhất. (ví dụ trên tôi dùng theo cách này)
  • Setter Injection: Các dependency sẽ được truyền vào 1 class thông qua các hàm Setter/Getter

Ví dụ ở trên tôi sẽ sửa phương thức getDao ở lớp DataProvider.java thành

  • Public fields: Các dependency sẽ được truyền vào 1 class một cách trực tiếp vào các public field. Cách này ít được sử dụng nhất. Ví dụ ở trên khi khai báo AbstractDao ở lớp DataProvider.java thành

4. Ưu nhược điểm của Dependency Injection

Ưu điểm
  • Giảm sự kết dính giữa các module
  • Code dễ bảo trì, dễ thay thế module
  • Rất dễ test và viết Unit Test
  • Dễ dàng thấy quan hệ giữa các module (Vì các dependecy đều được inject vào constructor)
Nhược điểm
  • Khái niệm DI hơi khó hiểu với người mới
  • Khó debug vì không biết implements nào của interface được gọi đến
  • Các object được khởi tạo từ đầu làm giảm performance
  • Làm tăng độ phức tạp của code

Do đó với những ứng dụng nhỏ gọn, làm ăn luôn thì ko nên áp dụng DI, còn những ứng dụng cần sự linh hoạt, mở rộng, maintain thì sử dụng DI.

5. Một số khái niệm khác

DI Container

  • DI Container là chỉ những thành phần tạo và quản lý module/object con được Inject, ví dụ ở trên là FactoryDAO.
  • Hiện tại có rất nhiều Framework và các thư viện hỗ trợ làm DI như CDI, Spring DI, JSF…

Inversion of Control

  • Inversion of Control dịch là đảo ngược điều khiển (hơi khó hiểu)
  • Ý của nó là làm thay đổi luồng điều khiển của ứng dụng. ví dụ như ở trên việc thay đổi thông tin trong file config.properties đã làm thay đổi luồng chạy của ứng dụng.

References:

https://en.wikipedia.org/wiki/Dependency_injection

https://stackoverflow.com/questions/130794/what-is-dependency-injection

 

Hy vọng qua bài viết bằng ví dụ minh họa cụ thể đã giúp các bạn học lập trình java hiểu rõ hơn về khái niệm Dependency Injection trong Java. Bên cạnh đó các bạn có thể tham gia học lập trình qua dự án cùng chuyên gia giỏi, giàu của Stanford, xem thêm ngay: tại đây

 

=============================
☎ STANFORD – ĐÀO TẠO VÀ PHÁT TRIỂN CÔNG NGHỆ
Hotline: 0963 723 236 – 0866 586 366
Website: https://stanford.com.vn
Facebook:
Youtube:

Nhận xét