1. Inversion of Control
Ở bài viết trước mình đã đề cập tới nguyên lý SOLID và nguyên lý cuối cùng trong SOLID chính là Dependency Inversion:
- 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
- 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.)
Nếu không áp dụng Dependency Inversion các module cấp cao phụ thuộc vào các module cấp thấp. Khi các module cấp thấp thay đổi thì các module cấp cao cũng phải thay đổi theo có thể dẫn tới thay đổi hàng loạt như vậy sẽ gây ra khó bảo trì.
Inversion of Control là một design pattern được tạo ra để các code tuân thủ nguyên lý Dependency Inversion. Có một vài mô hình được sử dụng để triển khai để triển khai Inversion of Control, bao gồm: Service Locator, Event, Dependency Injection.
2. Dependency Injection
Dependency Injection là một cách để hiện thực Inversion of Control Pattern. Các module cấp thấp sẽ được inject vào trong các module cấp cao.
Có ba loại Dependency Injection:
Constructer Injection: Các dependency sẽ được container truyền vào một class thông qua constructor của class đó.
class A {
public $b;
public function __construct(B $b)
{
$this->b = $b;
}
}
$a = new A(new B());
Setter Injection: Các dependency sẽ được truyền vào 1 class thông qua các hàm Setter.
class A {
public $b;
public function setB(B $b)
{
$this->b = $b;
}
}
Interface Injection: Class cần inject sẽ implement 1 interface. Interface này chứa 1 hàm tên Inject. Container sẽ injection dependency vào 1 class thông qua việc gọi hàm Inject của interface đó.
Ưu điểm của DI
- Giảm sự kết nối giữa các module
- Code dễ bảo trì, dễ sử dụng, thay thế module
- Dễ dàng cho việc viết test
Khuyết điểm của DI
- Khái niệm DI khá khó hiểu đối với người mới tìm hiểu.
- Làm cho code trở nên phức tạp khó hiểu hơn
- Các object được khởi tạo toàn bộ ngay từ đầu, có thể làm giảm performance.
3. Service Container
Bắt đầu ở phiên bản laravel thì đã có service container thay thế cho inversion of control container. Service container dùng để quản lý các dependencies và thực hiện dependency injection.
Binding
Hầu hết tất cả các Service Container binding của chúng ta sẽ được đăng ký trong Service Provider. Bên trong một Service Provider thì chúng ta luôn có quyền truy cập vào Container thông qua $this->app.
Simple Binding
$this->app->bind('Hello', function () {
return 'Hello';
});
Binding A Singleton
Instance sẽ chỉ được resolve một lần, những lần gọi tiếp theo sẽ không tạo ra instance mới mà chỉ trả về instance đã được resolve từ trước.
Instance Binding
Chúng ta có một instance đang tồn tại và chúng ta bind nó vào Service Container. Mỗi lần lấy ra chúng ta sẽ nhận lại được đúng instance đó.
$api = new \Hello\API(new HttpClient);
$this->app->instance('Hello\API', $api);
Resolve
Bạn có thể sử dụng phương thức make để lấy một instance ra khỏi container. Phương thức make nhận tên class hay tên interface bạn muốn resolve.
$api = $this->app->make('HelpSpot\API');
Nếu bạn không thể sử dụng biến $app
thì có thể sử dụng hàm helper resolve
để lấy ra instance.
$api = resolve('HelpSpot\API');
Qua quá trình tìm hiểu trên chúng ta có thể tổng kết lại là Service Container là nơi đăng ký và quản lý các dependency.
4. Kết luận
Cảm ơn các bạn đã theo dõi bài viết mong bài viết đem lại cho các bạn những kiến thức hữu ích. Hẹn gặp lại các bạn vào những bài viết tiếp theo.