07/09/2018, 08:46

Dependency Injection & Inversion Of Control

Xin chào mọi người, Vừa rồi mình có Lượn lờ vài blogs đọc được chút kiến thức hay ho và tổng hợp lại, mong nó giúp ích được cho nhiều người mới tiếp cần như mình =)). 1. Những nguyên lý thiết kế và viết code (nguyên lý SOLID) Nếu ai nắm vững được SOLID thì vứt đâu cũng sống được ( master ), ...

Xin chào mọi người, Vừa rồi mình có Lượn lờ vài blogs đọc được chút kiến thức hay ho và tổng hợp lại, mong nó giúp ích được cho nhiều người mới tiếp cần như mình =)).

1. Những nguyên lý thiết kế và viết code (nguyên lý SOLID)

Nếu ai nắm vững được SOLID thì vứt đâu cũng sống được (master), SOLID là tập hợp 5 nguyên tắc sau

  1. Single responsibility principle.
    Nguyên lý đầu tiên, tương ứng với chữ S trong SOLID.

    Một class chỉ nên giữ 1 trách nhiệm duy nhất (Chỉ có thể sửa đổi class với 1 lý do duy nhất)

    Vd thì nhiều nhưng cái này chắc dễ hiểu (ez)

  2. Open/closed principle.
    Nguyên lý thứ hai, tương ứng với chữ O trong SOLID.

    Có thể thoải mái mở rộng 1 class, nhưng không được sửa đổi bên trong class đó (open for extension but closed for modification).

    Khi thêm chức năng nên viết class mới mở rộng class cũ ( bằng cách kế thừa) không nên sửa đổi class cũ.

  3. Liskov substitution principle.
    Nguyên lý thứ ba, tương ứng với chữ L trong SOLID.

    Trong một chương trình, các object của class con có thể thay thế class cha mà không làm thay đổi tính đúng đắn của chương trình

    Cái này kkos hiểu v~, ví dụ có một class Nguoi, class Nam, Nu kế thừa class này chường trình chạy bình thường, nhưng class Bupbe_Annabelle kế thừa class này, vì không đi, chạy, nói được nên báo lỗi - điều này vi phạm nguyên lý này.

  4. Interface segregation principle.
    Nguyên lý thứ tư, tương ứng với chữ I trong SOLID.

    Thay vì dùng 1 interface lớn, ta nên tách thành nhiều interface nhỏ, với nhiều mục đích cụ thể

    Cái này cũng dễ hiểu đúng không.

  5. Dependency inversion principle.
    Nguyên lý cuối cùng, tương ứng với chữ D trong SOLID.

    Các class cấp cao không nên phụ thuộc vào các modules cấp thấp. Cả 2 nên phụ thuộc vào abstrac class.
    Interface (abstraction) không nên phụ thuộc vào chi tiết, mà ngược lại.( Các class giao tiếp với nhau thông qua interface)

    Nguyên lý này khá rườm rà, phần dưới sẽ nói rõ hơn về nó.

2. DEPENDENCY INJECTION VÀ INVERSION OF CONTROL

Mặc dù code, thực hiện chúng hằng ngày nhưng mình vẫn còn lơ ngơ về DIIoC. Hãy cùng nhìn lại nguyên lý Dependency inversion principle cuối cùng trong SOLID, đó chính là Dependency Inversion.

  1. Các module cấp cao không nên phụ thuộc vào các modules cấp thấp. Cả 2 nên phụ thuộc vào abstraction.
  1. Interface (abstraction) không nên phụ thuộc vào chi tiết, mà ngược lại. ( Các class giao tiếp với nhau thông qua interface, không phải thông qua implementation.)

Thông thường khi code, các class cấp cao sẽ gọi các class cấp thấp. Class cấp cao sẽ phụ thuộc và class cấp thấp, điều đó tạo ra các một sự phụ thuộc không hề nhẹ (dependency). Khi class cấp thấp thay đổi, class cấp cao phải thay đổi theo. Một thay đổi sẽ kéo theo hàng loạt thay đổi, giảm khả năng bảo trì của code.

Nếu tuân theo Dependendy Inversion principle, các class cùng phụ thuộc vào 1 interface không đổi. Ta có thể dễ dàng thay thế, sửa đổi class cấp thấp mà không ảnh hưởng gì tới class cấp cao.

Định Nghĩa

  • Dependency Inversion: Đây là một nguyên lý để thiết kếviết code.
  • Inversion of Control: Đây là một design pattern được tạo ra để code có thể tuân thủ nguyên lý Dependency Inversion. Dependency Injection là một cách thực hiện pattern này.
  • Dependency Injection: Đây là một cách để hiện thực Inversion of Control Pattern (Có thể coi nó là một design pattern riêng). Các class phụ thuộc (dependency) sẽ được truyền (inject) vào class cấp cao.

Dependency Injection:

  • Các class không giao tiếp trực tiếp với nhau, mà thông qua interface.
  • Class cấp thấp sẽ implement interface, class cấp cao sẽ gọi class cấp thấp thông qua interface.
  • Việc khởi tạo các class cấp thấp sẽ do DI Container thực hiện. Việc class nào gắn với interface nào sẽ được config trong code, trong laravel thì nó được thực hiện bởi Service Provider
  • DI được dùng để làm giảm sự phụ thuộc giữa các class, dễ dàng hơn trong việc thay đổi class, bảo trì code và testing.

Có 3 dạng Dependency Injection:

  1. Constructor Injection: Các dependency sẽ được container truyền vào (inject vào) 1 class thông qua constructor của class đó. Đây là cách thông dụng nhất.

  2. Setter Injection: Các dependency sẽ được truyền vào 1 class thông qua các hàm Setter.

  3. Interface Injection: Class cần inject sẽ implement 1 interface. Interface này chứa 1 hàm Inject. Container sẽ injection dependency vào 1 class thông qua việc gọi hàm Inject của interface đó. Đây là cách rườm rà, không thích chút nào.

Ưu điểm và Khuyết điểm của DI

DI không phải là vặn năng, nó cũng có những ưu điểm và khuyết điểm, do đó không phải project nào cũng nên áp dụng DI. Với những dự án lớn, code nhiều, DI là thứ rất cần thiết để đảm bảo code dễ bảo trì, dễ thay đổi. Vì vậy, bản thân các framework nổi tiếng như Laravel, ASP.NET MVC, … đều hỗ trợ hoặc tích hợp sẵn DI.

  1. ƯU ĐIỂM:
  • Giảm sự kết dính giữa các class
  • Code dễ bảo trì, dễ thay thế class
  • Rất dễ test và viết Unit Test
  • Dễ dàng thấy quan hệ giữa các class (Vì các dependecy đều được inject vào constructor)
  1. Nhược Điểm:
    Thưởng thức DI khá “khó nhai”.
  • Sử dụng interface nên đôi khi sẽ khó debug, do không biết chính xác class nào được gọi
  • Làm tăng độ phức tạp của code

Bài viết chủ yếu thiên về lý thuyết. Ở phần sau mình sẽ lấy ví dụ cụ thể.

Nguồn: https://toidicodedao.com

0