Một vòng laravel (Part 4)
Inversion Of Control Service Provider Contracts Facade 4 khái niệm core trong laravel IoC (Inversion of Control) IoC là một design pattern mà đi ngược lại với các design của lập trình truyền thống. Nếu với cách thức lập trình truyền thống, ta sẽ (khởi tạo và) gọi các dependency khi cần, ...
- Inversion Of Control
- Service Provider
- Contracts
- Facade 4 khái niệm core trong laravel
IoC (Inversion of Control)
IoC là một design pattern mà đi ngược lại với các design của lập trình truyền thống. Nếu với cách thức lập trình truyền thống, ta sẽ (khởi tạo và) gọi các dependency khi cần, thì với IoC, tất cả những thứ ta cần đều sẽ được truyền vào từ trước và ban sẽ gọi khi dùng đến. Ví dụ thế này, trong class Product, tôi cần dùng đến cả Category. Thì sẽ có sự khác nhau giữa lập trình có áp dụng IoC và không.
// not apply IoC class Product { public function addProductCategory($product) { $category = new Category(); $product->category = $category->find($product->category_id); return $product; } } // apply IoC class Product { public $category; public function __construct(Category $category) { $this->category = $category; } public function addProductCategory($product) { $product->category = $this->category; return $product; } }
Một trong những áp dụng tốt nhất của IoC là Dependency Injection. Và laravel thì áp dụng Dependency Injection (hay DI) một cách khá triệt để =)). (chính là service container)
Với DI (cũng có thể coi là 1 design pattern): ta vẫn áp dụng theo IoC, các dependency sẽ được inject vào constructor hoặc setter của class sử dụng nó. Nhưng các module (class) sẽ không giao tiếp tực tiếp với nhau, mà thông qua 1 interface.
Vẫn với ví dụ trên, ta sẽ không inject Category, mà sẽ là 1 CategoryInterface hoặc ICategory, còn việc Inject inteface nhưng vẫn có thể sử dụng được instance của Category, how and why thì do DI container xử lý. (tức là sẽ do các framework xử lý, ta ko cần phải lo).
// apply IoC class Product { public $category; public function __construct(CategoryInterface $category) { $this->category = $category; } public function addProductCategory($product) { $product->category = $this->category; return $product; } }
Với riêng trong laravel, ta sẽ cần phải bind CategoryInterface với Category, mục đích của việc này là để laravel biết rằng khi cần sử dụng tới CategoryInterface, nó sẽ inject instance của Category. Ta tiến hành bind trong AppServiceProvider
<?php namespace AppProviders; use IlluminateSupportServiceProvider; class AppServiceProvider extends ServiceProvider { /** * Bootstrap any application services. * * @return void */ public function boot() { // } /** * Register any application services. * * @return void */ public function register() { $this->app->bind('CategoryInterface', 'Category'); } }
Giờ thì ta sẽ chỉ việc khởi tạo 1 $product = new Product(), những thành phần còn lại ($$ategory) sẽ được tự động inject vào bởi laravel. (Lưu ý là Category sẽ phải implement CategoryInterface)
Việc sử dụng DI mạng lại rất nhiều lợi ích:
- Giảm sự phụ thuộc giữa các module. Giả sử hệ thống của ta đang sử dụng eloquent, và một ngày đẹp trời nào đó, khách hàng nói rằng, họ thấy query builder nhanh hơn, và muốn chuyển sang. Nếu sự phụ thuộc giữa các module với eloquent lớn, đó sẽ là 1 big problem. Nhưng vấn đề sẽ dễ giải quyết hơn nếu tất cả chỉ là 1 cái bind =)) . Ta sẽ tạo 1 class mới sử dụng query builder, và bind interface cũ với module này, và vấn đề được giải quyết awesome ha