6 Phút Để Hiểu Rõ Về Dependency Injection

Những dự án với độ phức tạp cao ngoài việc thiết kế tính năng cho ứng dụng, tổ chức code luôn luôn là vấn đề được đặt lên hàng đầu. Tổ chức tốt giúp lập trình viên dễ dàng bảo trì, cũng như mở rộng code về sau.

Để hoàn toàn có thể tiết kiệm chi phí ngân sách và thời hạn cho quy trình này nhưng vẫn đem lại hiệu suất cao cao, việc nắm vững về những design pattern sẽ giúp ích rất nhiều. Dependency Injection là một dạng design pattern được phong cách thiết kế với mục tiêu ngăn ngừa sự phụ thuộc vào giữa những class, để khiến cho code dễ hiểu hơn, trực quan hơn, nhằm mục đích ship hàng cho mục tiêu bảo dưỡng và tăng cấp code .
Tuy nhiên nếu sau khi đọc xong thuật ngữ trên bạn vẫn chưa hiểu gì thì hãy coi đây là chuyện thông thường vì những định nghĩa về một design pattern thường khá trừu tượng ( abstract ) mà không đi vào đơn cử. Việc đi sử dụng Dependency Injection như thế nào sẽ phụ thuộc vào vào cách tiến hành trong từng trường hợp đơn cử ( cũng như kỹ năng và kiến thức lập trình của developer ) .

Vậy Dependency Injection đơn cử là gì ?

Trước khi đi sâu tìm hiểu, hãy cùng xem qua một số khái niệm.

Theo Wikipedia:

“Trong kỹ thuật phần mềm, dependency injection là một kỹ thuật theo đó một đối tượng (hoặc static method) cung cấp các phụ thuộc của đối tượng khác. Một phụ thuộc là một đối tượng có thể được sử dụng (service).”

Nhưng nó vẫn khá khó hiểu, vậy hãy cũng làm rõ nó .
Đầu tiên, dependency hay dependent nghĩa là phụ thuộc vào vào tương hỗ của một cái gì, việc gì đó. Ví dụ như nếu tất cả chúng ta nhờ vào quá nhiều vào smartphone, thì hoàn toàn có thể hiểu là tất cả chúng ta đã dependent lên smartphone, tất cả chúng ta nhờ vào vào robot, đấy chính là tất cả chúng ta đã dependent lên robot .

Trước khi nói về dependency injection, hãy hiểu xem dependency trong lập trình nghĩa là gì trước.

Khi mà class A sử dụng một số chức năng của class class B, thì có thể nói là class A có quan hệ phụ thuộc với class B.

Trong java, trước khi ta có thể sử dụng method của class khác, ta phải khởi tạo một object của class đấy (hay A cần phải tạo 1 thực thể của B). Vậy ta có thể hiểu, việc chuyển giao nhiệm vụ khởi tạo object đó cho một ai khác và trực tiếp sử dụng các dependency đó được gọi là dependency injection.

Hay nói một cách đúng chuẩn và khách quan hơn là :

Dependency injection (DI) là một kỹ thuật lập trình giúp tách một class độc lập với các biến phụ thuộc. Với lập trình hướng đối tượng, chúng ta hầu như luôn phải làm việc với rất nhiều class trong một chương trình. Các class được liên kết với nhau theo một mối quan hệ nào đó. Dependency là một loại quan hệ giữa 2 class mà trong đó một class hoạt động độc lập và class còn lại phụ thuộc bởi class kia.

Nếu nó là design pattern, vậy có mấy loại Dependency Injection ? 

Thông thường, tất cả chúng ta chỉ thường gặp ba loại Dependency Injection sau :

  • Constructor injection: Các dependency ( biến phụ thuộc vào ) được cung ứng trải qua constructor ( hàm tạo lớp ) .
  • Setter injection: Các dependency (biến phụ thuộc) sẽ được truyền vào 1 class thông qua các setter method (hàm setter).

  • Interface injection: Dependency sẽ cung cấp một Interface, trong đó có chứa hàm có tên là Inject.  Các client phải triển khai một Interface mà có một setter method dành cho việc nhận dependency và truyền nó vào class thông qua việc gọi hàm 

    Inject

     của Interface đó.

Vậy đơn cử trách nhiệm của Dependency Injection là :

  1. Tạo ra các object.
  2. Biết được class nào cần những object đấy.
  3. Cung cấp cho những class đó những object chúng cần.

Bên cạnh đó, những bạn cũng nên quan tâm tới 1 số ít khái niệm tương tự như như Dependency Inversion, Inversion of Control ( IoC ), Dependency Injection ( DI ). Ba khái niệm này tương tự như nhau nhưng không trọn vẹn giống nhau, nếu hoàn toàn có thể, bạn nên khám phá từng cái để tránh những lẫn lộn không thiết yếu .

IoC là hướng đi, DIP là định hình cụ thể của hướng đi, còn DI là một hiện thực cụ thể.

Tại sao phải dùng Dependency Injection ? Khi nào dùng tới nó ? Thực hiện nó ra sao ?

Dependency Injection hoàn toàn có thể được thực thi dựa trên những quy tắc sau :

  • Các class sẽ không phụ thuộc trực tiếp lẫn nhau mà thay vào đó chúng sẽ liên kết với nhau thông qua một Interface hoặc base class (đối với một số ngôn ngữ không hỗ trợ Interface)
  • Việc khởi tạo các class sẽ do các Interface quản lí thay vì class phụ thuộc nó

Giả sử, chúng ta có một class Car, trong đó có vài object khác như Wheel, hay Battery:

class Car{
  private Wheels wheel = new MRFWheels();
  private Battery battery = new ExcideBattery();
  ...
  ...
}

Ở đây, class Car chịu trách nhiệm khởi tạo tất cả các dependency object. Nhưng chuyện gì sẽ xảy ra nếu chúng ta muốn bỏ MRFWheels và thay thế bằng BMWWheels.

Lúc này chúng ta phải tạo lại đối tượng car mới với phụ thuộc mới (new dependecy) là BMWWheels. Rồi sau này nữa, bạn lại muốn độ bánh xe lên, hay thay bánh khác thì sao??? Mỗi lần vậy thêm một loạt code và khi đó chưa chắc chúng đã chạy được, chưa kể là cực kỳ khó đọc.

Dependency Injection là một dạng design pattern được thiết kế nhằm ngăn chặn sự phụ thuộc nêu trên, khi sử dụng dependency injection, chúng ta có thể đổi wheel ở runtime vì dependency có thể được truyền vào (inject) ở runtime thay vì complile time, điều này giúp giảm chi phí trong việc sửa đổi và nâng cấp hệ thống. Nhờ vậy khi bạn thực thiện thay đổi một class A thì những class chứa biến kiểu class A cũng không cần phải thay đổi theo. 

Bạn có thể hiểu là dependency injection là một người trung gian chịu trách nhiệm tạo ra các loại wheel khác nhau, rồi cung cấp chúng cho class Car. Việc đó làm cho class Car ko phải phụ thuộc vào Wheels cụ thể nào hay Battery cụ thể nào nữa.

class Car{
  private Wheels wheel;
  private Battery battery;
  
  /*Ở đâu đó trong project, ta khởi tạo những objects mà đc yêu cầu bởi class này
    Có 2 cách để implement dependency injection
    1. Dựa vào constructor
    2. Dựa vào Setter method
  */
  
  // Dựa vào constructor
  Car(Wheel wh, Battery bt) {
    this.wh = wh;
    this.bt = bt;
  }
  
  // Dựa vào Setter method
  void setWheel(Batter bt){
    this.bt = bt;
  }
  ...  
  ...
}

Lợi ích và bất cập khi dùng Dependency Injection

Lợi ích khi dùng Dependency Injection:

  • Dễ test và viết Unit Test: Dễ hiểu là khi ta có thể Inject các dependency vào trong một class thì ta cũng dễ dàng “tiêm” các mock object vào class (được test) đó.
  • Dễ dàng thấy quan hệ giữa các object: Dependency Injection sẽ inject các object phụ thuộc vào các interface thành phần của object bị phụ thuộc nên ta dễ dàng thấy được các dependency của một object.
  • Dễ dàng hơn trong việc mở rộng các ứng dụng hay tính năng.
  • Giảm sự kết dính giữa các thành phần, tránh ảnh hưởng quá nhiều khi có thay đổi nào đó.

Bất lợi của Dependency Injection:

  • Nó khá là phức tạp để học, và nếu dùng quá đà thì có thể dẫn tới một số vấn đề khác.
  • Rất nhiều các lỗi ở compile time có thể bị đẩy sang runtime, dẫn đến đôi khi sẽ khó debug. Vì sử dụng nhữngInterfacenên hoàn toàn có thể gặp khó khăn vất vả khi ta debug source code vì không biết implement nào thực sự được truyền vào .
  • Có thể làm ảnh hưởng tới chức năng auto-complete hay find references của một số IDE. Cụ thể vì Dependency Injection ẩn những dependency nên một số ít lỗi chỉ xảy ra khi chạy chương trình thay vì hoàn toàn có thể phát hiện khi biên dịch chương trình .
  • Khó khăn lớn nhất là khi người mới vào làm bằng DI sẽ không hiểu rõ ràng tư tưởng, khiến quá trình làm DI vẫn bị nhập nhằng và các injector bị ràng buộc mà không thoát hẳn ra theo tư tưởng của DI.

Tạm kết

Bên trên mình đã tổng kết lại một số ít kỹ năng và kiến thức về Dependency Injection qua những thông tin mình tìm kiếm được trên mạng, kỳ vọng bài viết giúp ích được phần nào cho mọi người. Nếu có sai sót, xin hãy để lại phản hồi phía bên dưới, mình sẽ update nhanh nhất hoàn toàn có thể .
Sự ủng hộ của mọi người là động lực để mình liên tục cho ra những bài viết tiếp theo. Cảm ơn mọi người !

5/5 - (1 vote)

Bài viết liên quan

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments