[Design Patterns #3] Factory Pattern – Phần 1: Factory Method

Factory Pattern bao gồm 2 patterns là Factory Method và Abstract Factory. Ở phần 1 của Factory Pattern này mình sẽ giới thiệu và phân tích về Factory Method trong Factory Pattern.

Bài toán cần giải quyết

Lại nói về vấn database để lấy ví dụ. Giả sử, ở hiện tại, để tạo một database connection object các dev của chúng ta đang làm như sau →

Sau khi tạo connection chúng ta có thể connect đến Oracle databases. Nhưng nếu bây giờ khách hàng muốn đổi sang dùng Microsoft’s SQL Server databases thì sao ? 

OK, chúng sẽ phải tạo class SqlServerConnection (cùng interface với OracleConnection) và sửa lại đoạn code tạo connection sang dùng class mới →

Vào một ngày đẹp trời, à không, xấu trời mới đúng, khách hàng lại muốn đổi sang MySQL databases thì như nào ? Lại phải tạo ra class mới MySqlConnection (cùng interface với OracleConnection, SqlServerConnection) và lại đổi sang dùng nó để tạo connection thôi →

Áp dụng Factory Method

Bây giờ chúng ta đã có ba loại database connection khác nhau là: Oracle, SQL ServerMySQL. Vì vậy, chúng ta nên điều chỉnh lại code để tạo connection một cách linh hoạt hơn để đối phó với sự thay đổi có thể xảy ra trong tương lai. Chúng ta sẽ tạo instance của connection dựa vào giá trị trong một biến là connectionType (giá trị của connectionType được set vào trước khi tạo connection).

*** khai báo enum cho connection types *** tạo interface chung cho các connection class *** tạo instance của connection dựa trên connection type

Tạm ổn. Tuy nhiên trong chương trình có thể rất nhiều chỗ cần tạo database connection, nếu có khoảng 200 chỗ cần tạo database connection chúng ta sẽ có khoảng 200 đoạn code switch case như ở trên ==> ngu học. Đã đến lúc đặt đoạn code tạo connection vào một method của một class để tránh trùng lặp code (nguyên tắc DRY – Don’t Repeat Yourseft) và dễ maintain →

Hàm DbConnectionFactory::createConnection chính là cái gọi là Factory Method dùng để tạo ra connection instance dựa trên tham số truyền vào. Bây giờ chúng ta có thể tạo instance của connection theo cách sau →

*** class diagram  

Ưu điểm của việc sử dụng Factory Method

  • Tách biệt công việc tạo object / instance ra khỏi xử lý của client code (client code là phần code sử dụng object / instance để thực hiện hoàn thành công việc của nó). Client code sẽ không cần phải quan tâm instance được tạo ra như thế nào, nó là object của class nào, nhờ đó giảm thiểu dependency của client code (Nguyên tắc: Loose Coupling).
  • Dễ maintain: nếu muốn thêm/bớt các connection class, sửa tên connection class thì chỉ cần sửa một method mà không làm ảnh hưởng đến các phần code khác. (vd: trong trường hợp connection instance ở trên thì chỉ cần sửa hàm DbConnectionFactory::createConnection)

Note

Trong bài này mình đưa ra cách tiếp cận dựa theo cuốn sách Design Patterns for Dummies nên sẽ hơi khác một chút so với cách tiếp cận thông thường theo cuốn Design Pattern – Elements Reusable Object-Oriented Software. Vì theo kinh nghiệm của mình thì cách tiếp cận này dễ hiểu, hợp lý hơn, nếu bạn nào muốn tìm hiểu thêm theo cách tiếp cận khác thì có thể tham khảo cuốn sách mình vừa mention ở trên.

Ở bài tiếp theo mình sẽ tiếp tục giới thiệu tới mọi người pattern thứ 2 trong Factory Pattern là Abstract Factory.

— Phạm Minh Tuấn (Shun) —