Tại sao ShapeFactory này sử dụng các câu lệnh có điều kiện để xác định đối tượng nào sẽ khởi tạo. Chúng ta không phải sửa đổi ShapeFactory nếu chúng ta muốn thêm các lớp khác trong tương lai? Tại sao điều này không vi phạm nguyên tắc đóng mở?
Tại sao ShapeFactory này sử dụng các câu lệnh có điều kiện để xác định đối tượng nào sẽ khởi tạo. Chúng ta không phải sửa đổi ShapeFactory nếu chúng ta muốn thêm các lớp khác trong tương lai? Tại sao điều này không vi phạm nguyên tắc đóng mở?
Câu trả lời:
Sự khôn ngoan hướng đối tượng thông thường là tránh các if
câu lệnh và thay thế chúng bằng cách gửi động các phương thức được ghi đè trong các lớp con của một lớp trừu tượng. Càng xa càng tốt.
Nhưng quan điểm của mẫu nhà máy là giúp bạn không phải biết về các lớp con riêng lẻ và chỉ làm việc với siêu lớp trừu tượng . Ý tưởng là nhà máy biết rõ hơn bạn về lớp cụ thể nào để khởi tạo và bạn sẽ làm việc tốt hơn chỉ với các phương thức được xuất bản bởi siêu hạng. Điều này thường đúng và là một mô hình có giá trị.
Do đó, không có cách nào để viết một lớp nhà máy có thể từ bỏ các if
tuyên bố. Nó sẽ chuyển gánh nặng của việc chọn một lớp cụ thể cho người gọi, đó chính xác là những gì mô hình được cho là nên tránh. Không phải tất cả các nguyên tắc là tuyệt đối (trên thực tế, không có nguyên tắc nào là tuyệt đối) và nếu bạn sử dụng mẫu này, bạn sẽ cho rằng lợi ích từ nó lớn hơn lợi ích của việc không sử dụng if
.
if
s. Xem câu trả lời của @ BЈовић để biết ví dụ đơn giản về cách đạt được điều này. Bị hạ bệ.
Ví dụ có thể sử dụng một tuyên bố có điều kiện bởi vì nó là đơn giản nhất. Việc triển khai phức tạp hơn có thể sử dụng bản đồ hoặc cấu hình hoặc (nếu bạn muốn thực sự ưa thích) một số loại đăng ký mà các lớp có thể tự đăng ký. Tuy nhiên, không có gì sai khi sử dụng một điều kiện nếu số lượng lớp nhỏ và thay đổi không thường xuyên.
Mở rộng điều kiện để thêm hỗ trợ cho một lớp con mới trong tương lai thực sự sẽ nói đúng là vi phạm nguyên tắc mở / đóng. Giải pháp "chính xác" sẽ là tạo ra một nhà máy mới có cùng giao diện. Điều đó nói rằng, việc tuân thủ nguyên tắc O / C phải luôn được cân nhắc với các nguyên tắc thiết kế khác như KISS và YAGNI.
Điều đó nói rằng, mã được hiển thị là mã ví dụ rõ ràng được thiết kế để hiển thị khái niệm về một nhà máy và không có gì khác. Ví dụ, phong cách thực sự xấu khi trả về null như ví dụ, nhưng xử lý lỗi phức tạp hơn sẽ chỉ làm mờ điểm. Mã ví dụ không phải là mã chất lượng sản xuất, bất kỳ mã nào bạn không nên mong đợi.
Bản thân mẫu không vi phạm Nguyên tắc Mở / Đóng (OCP). Tuy nhiên, chúng tôi vi phạm OCP khi chúng tôi sử dụng mẫu không chính xác.
Câu trả lời đơn giản cho câu hỏi này như sau:
Trong ví dụ được cung cấp, chức năng cơ sở của bạn hỗ trợ ba hình dạng: Hình tròn, Hình chữ nhật và Hình vuông. Giả sử bạn cần hỗ trợ Tam giác, Lầu năm góc và Lục giác trong tương lai. Để làm điều này mà KHÔNG vi phạm OCP, bạn phải tạo một nhà máy bổ sung để hỗ trợ các hình dạng mới của bạn (hãy gọi AdvancedShapeFactory
) và sau đó sử dụng AbstractFactory để quyết định nhà máy nào bạn cần tạo để tạo bất kỳ hình dạng nào bạn cần.
Nếu bạn đang nói về mẫu Tóm tắt của Nhà máy, việc đưa ra quyết định thường không nằm trong chính Nhà máy mà là mã ứng dụng. Đó là mã chọn nhà máy cụ thể để khởi tạo và chuyển qua mã máy khách sẽ sử dụng các đối tượng do Nhà máy sản xuất. Xem phần cuối của ví dụ Java tại đây: https://en.wikipedia.org/wiki/ Ab khu_factory_potype
Ra quyết định không nhất thiết ngụ ý if
tuyên bố. Nó có thể đọc loại Factory Factory cụ thể từ một tệp cấu hình, xuất phát từ cấu trúc bản đồ, v.v.
Nếu bạn nghĩ về Open-Close ở cấp độ lớp với nhà máy này, thì bạn đang tạo một lớp khác trong hệ thống của bạn Open-Close, ví dụ nếu bạn có một lớp khác lấy một Hình dạng và tính diện tích (ví dụ điển hình) thì lớp này là OpenClose vì nó có thể tính diện tích cho các loại hình mới mà không cần sửa đổi. Sau đó, bạn có một lớp khác vẽ hình dạng, một lớp khác có hình dạng N và trả về hình lớn hơn và bạn có thể nghĩ chung rằng các lớp khác trong hệ thống của bạn có hình dạng là Open-Close (ít nhất là về hình dạng). Nhìn vào thiết kế, nhà máy cho phép phần còn lại của hệ thống là Open-Close và tất nhiên là chính nhà máy ITS KHÔNG Open-Close.
Dĩ nhiên, bạn cũng có thể làm cho nhà máy này đóng mở, thông qua một số loại tải động và toàn bộ hệ thống của bạn có thể là Đóng mở (ví dụ, bạn có thể thêm hình dạng mới thả một số jar trong đường dẫn lớp). Bạn cần đánh giá mức độ phức tạp thêm này có giá trị tùy thuộc vào hệ thống mà bạn đang xây dựng, không phải tất cả các hệ thống đều cần các tính năng có thể cắm và không phải tất cả hệ thống đều cần phải đóng mở hoàn toàn.
Nguyên tắc đóng mở, như nguyên tắc thay thế Liskov, áp dụng cho các cây lớp, cho hệ thống phân cấp thừa kế. Trong ví dụ của bạn, lớp nhà máy không nằm trong cây gia đình của các lớp mà nó khởi tạo để nó không thể vi phạm các quy tắc này. Sẽ có vi phạm nếu GetShape của bạn (hoặc được đặt tên thích hợp hơn là CreatShape) được triển khai trong lớp cơ sở Shape.
Tất cả phụ thuộc vào cách bạn thực hiện nó. Bạn có thể sử dụng std::map
để giữ các con trỏ hàm đến các hàm tạo đối tượng. Sau đó, nguyên tắc mở / đóng không bị vi phạm. Hoặc chuyển đổi / trường hợp.
Dù sao, nếu bạn không thích mẫu nhà máy, bạn luôn có thể sử dụng phương pháp tiêm phụ thuộc.