Nội dung
Mục tiêu
Factory Method là một mẫu thiết kế khởi tạo cung cấp một interface để tạo các đối tượng trong một lớp cha, nhưng cho phép các lớp con thay đổi loại đối tượng sẽ được tạo.
Đặt vấn đề
Hãy tưởng tượng rằng bạn đang tạo một ứng dụng quản lý logistics. Phiên bản đầu tiên của ứng dụng chỉ có thể xử lý việc vận chuyển bằng xe tải, vì vậy phần lớn chương trình của bạn nằm trong lớp Truck
.
Sau một thời gian, ứng dụng của bạn trở nên khá phổ biến. Mỗi ngày, bạn nhận được hàng chục yêu cầu từ các công ty vận tải đường biển để kết hợp dịch vụ logistics đường biển vào ứng dụng.
Tin tuyệt vời, phải không? Nhưng làm thế nào về chương trình? Hiện tại, hầu hết mã của bạn được liên kết với lớp Truck
. Thêm Ship
vào ứng dụng sẽ yêu cầu thực hiện các thay đổi đối với toàn bộ codebase. Hơn nữa, nếu sau này bạn quyết định thêm một loại phương tiện di chuyển khác vào ứng dụng, có thể bạn sẽ cần thực hiện lại tất cả những thay đổi này. Kết quả là, bạn sẽ nhận được mã khá khó chịu, có nhiều điều kiện thay đổi hành vi của ứng dụng tùy thuộc vào loại đối tượng vận chuyển.
Giải pháp
Mẫu Factory Method gợi ý rằng bạn nên thay thế các lệnh gọi khởi tạo đối tượng trực tiếp (sử dụng toán tử new) bằng các lệnh gọi đến một phương thức factory đặc biệt. Đừng lo lắng, các đối tượng vẫn được tạo thông qua toán tử new, nhưng nó đang được gọi từ trong Factory Method. Các đối tượng được trả về theo Factory Method thường được gọi là product.
Thoạt nhìn, thay đổi này có vẻ vô nghĩa, chúng ta vừa chuyển lời gọi hàm khởi tạo từ phần này sang phần khác của chương trình. Tuy nhiên, hãy xem xét điều này, bây giờ bạn có thể ghi đè phương thức gốc trong một lớp con và thay đổi lớp product đang được tạo bởi phương thức này.
Tuy nhiên, có một hạn chế nhỏ là các lớp con có thể trả về các loại product khác nhau chỉ khi các product này có lớp cơ sở hoặc interface chung. Ngoài ra, phương thức factory trong lớp cơ sở nên có kiểu trả về được khai báo là interface này.
Ví dụ, cả hai lớp Truck
và Ship
nên triển khai interface Transport
, interface này khai báo một phương thức được gọi là deliver
. Mỗi lớp thực hiện phương thức này khác nhau: xe tải chuyển hàng bằng đường bộ, tàu giao hàng bằng đường biển. Phương thức factory trong lớp RoadLogistics trả về các đối tượng xe tải, trong khi phương thức factory trong lớp SeaLogistics trả về các tàu.
Mã sử dụng phương thức factory (thường được gọi là mã client) không thấy sự khác biệt giữa các product thực tế được trả về bởi các lớp con khác nhau. Client coi tất cả các product là Transport trừu tượng. Client biết rằng tất cả các đối tượng truyền tải đều phải có phương thức deliver
, nhưng chính xác cách thức hoạt động của nó không quan trọng đối với client.
Cấu trúc
- Product khai báo interface, interface này là chung cho tất cả các đối tượng có thể được tạo bởi creator và các lớp con của nó.
- Concrete Product là các triển khai khác nhau của interface Product.
- Lớp Creator khai báo phương thức factory trả về các đối tượng product mới. Điều quan trọng là kiểu trả về của phương thức này phải phù hợp với interface Product.
Bạn có thể khai báo phương thức factory là trừu tượng để buộc tất cả các lớp con triển khai các phiên bản riêng của phương thức đó. Thay vào đó, phương thức factory cơ sở có thể trả về một số kiểu product mặc định. - Concrete Creator ghi đè phương thức gốc của factory để nó trả về một kiểu product khác.
Khả năng áp dụng
- Sử dụng phương thức factory khi bạn không biết trước chính xác các kiểu và các phụ thuộc của các đối tượng mà mã của bạn sẽ hoạt động.
- Sử dụng phương thức factory khi bạn muốn cung cấp cho người dùng thư viện hoặc framework của mình một cách để mở rộng các thành phần bên trong của nó.
- Sử dụng phương thức factory khi bạn muốn tiết kiệm tài nguyên hệ thống bằng cách sử dụng lại các đối tượng hiện có thay vì xây dựng lại chúng mỗi lần thêm kiểu đối tượng mới.
Ưu và nhược điểm
😄 Tránh kết nối chặt chẽ giữa creator và các concrete creator.
😄 Nguyên tắc Đơn trách nhiệm. Bạn có thể di chuyển mã tạo product vào một nơi trong chương trình, giúp mã hỗ trợ dễ dàng hơn.
😄 Nguyên tắc Mở / Đóng. Bạn có thể giới thiệu các kiểu product mới vào chương trình mà không cần phá vỡ mã client hiện có.
🙁 Mã có thể trở nên phức tạp hơn vì bạn cần phải giới thiệu nhiều lớp con mới để triển khai mẫu. Kịch bản tốt nhất là khi bạn đưa mẫu vào hệ thống phân cấp hiện có của các lớp creator.
Mối quan hệ với các mẫu khác
Nhiều thiết kế bắt đầu bằng cách sử dụng Factory Method (ít phức tạp hơn và có thể tùy chỉnh nhiều hơn thông qua các lớp con) và phát triển theo hướng Abstract Factory, Prototype hoặc Builder (linh hoạt hơn nhưng phức tạp hơn).
Các lớp Abstract Factory thường dựa trên một tập các phương thức factory, nhưng bạn cũng có thể sử dụng Prototype để hợp các phương thức trên các lớp này.
Bạn có thể sử dụng Factory Method cùng với Iterator để cho phép tập hợp các lớp con trả về các kiểu lặp khác nhau tương thích với tập hợp.
Prototype không dựa trên tính kế thừa, vì vậy nó không có nhược điểm. Nói cách khác, Prototype yêu cầu khởi tạo phức tạp cho đối tượng được nhân bản. Factory Method dựa trên sự kế thừa nhưng không yêu cầu bước khởi tạo.
Phương thức factory là một sự đặc biệt của Template Method. Đồng thời, Phương thức factory có thể đóng vai trò như một bước của phương thức template.
Chương trình mẫu
C++ Design patterns: Factory Method
Để lại một bình luận