Seri này forcus vào các vấn đề sau:
- Inversion of Control (IoC),
- Dependency Inversion Principle (DIP),
- Dependency Injection (DI),
- IoC containers.
I. Design parten and Design principle
IoC, DIP là high level design principle, nên chúng được sử dụng trong việc design lớp ứng dụng, chúng không cung cấp bất cứ chi tiết implementation cụ thể nào.
Design principle cung cấp high level để thiết kế ứng dụng tốt hơn. Chúng không cung cấp implementation (thực thi), và không ràng buộc bất cứ ngôn ngữ nào. SOLID (SRP, OCP, LSP, ISP, DIP) principles là một trong những desgin principle phổ biến.
Design pattern cung cấp low-level solution liên quan tới việc implementation, của các vấn đề chung trong hướng đối tượng. Nói cách khác, design pattern là mẫu, chuẩn về việc implementation trong lập trình hướng đối tượng.
Ví dụ: Abstract Factory, Factory, Singleton, Command,...
IoC, DIP là high level design principle, nên chúng được sử dụng trong việc design lớp ứng dụng, chúng không cung cấp bất cứ chi tiết implementation cụ thể nào.
DI là pattern còn IoC container là framework, là implementation.
II. Ioc - Inversion of Control
IOC là 1 design principle, giống như tên gọi của nó, Nó được dùng để đảo ngược cái loại điều khiển trong thiếu kế hướng đối tượng để để giảm bớt sự phụ thuộc. Ở đây, các điều khiển đề cập đến các trách nhiệm bổ sung trong một class, ngoài trách nhiệm chính của nó. Điều này bao gồm kiểm soát luồng của ứng dụng và kiểm soát luồng của việc tạo đối tượng hoặc tạo và ràng buộc đối tượng phụ thuộc.
Có thể hiêu IoC thông qua ví dụ dưới đây:
Giả sử A đi làm bằng car, A tự lái xe tới công ty nghĩa là A control car. Nguyên tắc IoC là đảo ngược điều khiển, nghĩa là thay vì tự lái xe, A thuê taxi, sẽ có một tài xế lái xe. Do đó, điều này được gọi là IoC - đảo ngược điều khiển - từ A đến tài xế taxi. A không phải tự lái xe và A có thể để tài xế lái xe, A có thể tập trung vào công việc chính của mình.
III. Sử dụng factory pattern
Factory Pattern
Có thể hiêu IoC thông qua ví dụ dưới đây:
Giả sử A đi làm bằng car, A tự lái xe tới công ty nghĩa là A control car. Nguyên tắc IoC là đảo ngược điều khiển, nghĩa là thay vì tự lái xe, A thuê taxi, sẽ có một tài xế lái xe. Do đó, điều này được gọi là IoC - đảo ngược điều khiển - từ A đến tài xế taxi. A không phải tự lái xe và A có thể để tài xế lái xe, A có thể tập trung vào công việc chính của mình.
III. Sử dụng factory pattern
Factory Pattern
Một Factory Pattern hoặc là Factory Method Pattern chỉ định nghĩa 1 interfce hoặc abstract class cho việc tạo 1 đối tượng nhưng để các subclasses quyết định class nào sẽ được tạo. Hay nói cách khác, subclasses có trách nhiệm tạo ra instance của class.
Dưới đây là một ví dụ áp dụng IoC sử dụng Factory pattern:
Ở đây mình có 2 class là CustomerBusinessLogic và 1 lớp DataAcces như bên dưới:
Lớp CustomerBusinessLogic phụ thuộc vào lớp DataAccess. Nó sẽ tạo ra 1 đối tượng của DataAccess để sử dụng các method public ở trong lớp DataAccess, cụ thể ở đây là sử dụng method GetCustomerName đẻ lấy dữ liệu khách hàng (customer data).
Ở đây mình có 2 class là CustomerBusinessLogic và 1 lớp DataAcces như bên dưới:
public class CustomerBusinessLogic
{
DataAccess _dataAccess;
public CustomerBusinessLogic()
{
_dataAccess = new DataAccess();
}
public string GetCustomerName(int id)
{
return _dataAccess.GetCustomerName(id);
}
}
public class DataAccess
{
public DataAccess()
{
}
public string GetCustomerName(int id) {
return "Dummy Customer Name"; // get it from DB in real app
}
}
Lớp CustomerBusinessLogic phụ thuộc vào lớp DataAccess. Nó sẽ tạo ra 1 đối tượng của DataAccess để sử dụng các method public ở trong lớp DataAccess, cụ thể ở đây là sử dụng method GetCustomerName đẻ lấy dữ liệu khách hàng (customer data).
Cách này không có sai và chương trình vấn chạy bình thường, nhưng nó sẽ khó maintain, và sẽ phát sinh một vấn đề sau:
Lớp CustomerBusinessLogic và DataAccess được gọi là "liên kết chắt chẽ" bởi vì lớp CustomerBusinessLogic chứa tham chiếu của của lớp DataAccess. Và nó cũng tạo ra một đối tượng của lớp DataAccess.
Và vấn đề của ví dụ này là:
1. Vì CustomerBusinessLogic và DataAccess là các lớp liên kết chắt chẽ, Vì vậy khi DataAccess thay đổi sẽ dẫn đến sự thay đổi CustomerBusinessLogic . Ví dụ khi thêm hoặc thay đổi bất kỳ method trong lớp DataAccess và chúng ta cần thay đổi lớp CustomerBusinessLogic cho phù hợp.
2. Giả sử dữ liệu khách hàng đến từ những database khác nhau hoặc là từ một web service nào đó, trong tương lai, có thể chúng ta cần tạo ra những class khác nhau. Vì thể nó sẽ ảnh hưởng tới sự thay đổi trong lớp CustomerBusinessLogic.
3. Lớp CustomerBusinessLogic tạo ra 1 đối tượng của lớp DataAccess, sử dụng từ khóa new. Có thể có nhiều lớp sử dụng lớp DataAcess và tạo ra đổi tưởng của nó. Nếu như thay đổi tên class thì chúng ta cần tìm tất cả các class có sử dụng DataAccess để sửa. Đây là là đoạn code lặp đi lắp lại đẻ tạo ra đối tượng của cùng một lass và duy trì sự phụ thuộc.
4. Bởi vì lớp CustomerBusinessLogic tạo ra một đối tượng của lớp DataAccess. Nó không thể test độc lập (TDD). Lớp DataAccess không thể thay thể với 1 mock class (có thể tìm hiểu mock test).
Để giải quyết những vẫn đề trên và nới lỏng liên kết. Chúng ta có thể sử dụng IoC và DIP principle (bài sau) cùng nhau. Nên nhớ, Ioc là một principle, không phải là một Pattern. Nó chỉ cung cấp high-level desig nhưng không cung cấp chi tiết implemenetation (thực thi). Chúng ta có thể tự do implement IoC principle theo cách mà chúng ta muốn.
Pattern implement của Ioc:
Đầu tiên tạo một lớp Factory trả về một đối tượng của DataAccess như bên dưới:
2. Giả sử dữ liệu khách hàng đến từ những database khác nhau hoặc là từ một web service nào đó, trong tương lai, có thể chúng ta cần tạo ra những class khác nhau. Vì thể nó sẽ ảnh hưởng tới sự thay đổi trong lớp CustomerBusinessLogic.
3. Lớp CustomerBusinessLogic tạo ra 1 đối tượng của lớp DataAccess, sử dụng từ khóa new. Có thể có nhiều lớp sử dụng lớp DataAcess và tạo ra đổi tưởng của nó. Nếu như thay đổi tên class thì chúng ta cần tìm tất cả các class có sử dụng DataAccess để sửa. Đây là là đoạn code lặp đi lắp lại đẻ tạo ra đối tượng của cùng một lass và duy trì sự phụ thuộc.
4. Bởi vì lớp CustomerBusinessLogic tạo ra một đối tượng của lớp DataAccess. Nó không thể test độc lập (TDD). Lớp DataAccess không thể thay thể với 1 mock class (có thể tìm hiểu mock test).
Để giải quyết những vẫn đề trên và nới lỏng liên kết. Chúng ta có thể sử dụng IoC và DIP principle (bài sau) cùng nhau. Nên nhớ, Ioc là một principle, không phải là một Pattern. Nó chỉ cung cấp high-level desig nhưng không cung cấp chi tiết implemenetation (thực thi). Chúng ta có thể tự do implement IoC principle theo cách mà chúng ta muốn.
Pattern implement của Ioc:
Đầu tiên tạo một lớp Factory trả về một đối tượng của DataAccess như bên dưới:
public class DataAccessFactory
{
public static DataAccess GetDataAccessObj()
{
return new DataAccess();
}
}
Bây giờ sử dụng lớp Factory trong lớp CustomerBusinessLogic để lấy đối tượng DataAccess.public class CustomerBusinessLogic
{
public CustomerBusinessLogic()
{
}
public string GetCustomerName(int id)
{
DataAccess _dataAccess = DataAccessFactory.GetDataAccessObj();
return _dataAccess.GetCustomerName(id);
}
}
Như chúng ta thấy lớp CustomerBusinessLogic sử dụng method DataAccessFactory.GetCustomerDataAccessObj() để lấy đối tượng của lớp DataAccess thay vì sử dụng từ khóa new, Do vậy, chúng ta đã đảo ngược điều khiển việc tạo ra một đối tượng của một lớp phụ thuộc từ CustomerBusinessLogic sang lipws DataAccessFactory. Đây là một ví dụ đơn giản về IoC và bước đầu để đạt được hướng tới thiếu kế loose coupled. Chúng ta sẽ không hoàn toàn tách các lớp phụ thuộc, nới lòng chỉ bằng cách sử dụng IoC. Và kèm với IoC thì chúng ta cần sử dụngDIP, Strategy pattern, và DI (Dependency Injection).
Để lại bình luận cho trang này