2009-03-10 35 views
132

Khi mô hình hóa các lớp học, cách ưa thích của khởi tạo là gì:Constructors vs Phương pháp Factory

  1. Constructors, hoặc phương pháp
  2. Factory

Và điều gì sẽ cân nhắc cho việc sử dụng một trong hai trong số họ ?

Trong một số trường hợp nhất định, tôi muốn có phương thức factory trả về null nếu đối tượng không thể được xây dựng. Điều này làm cho mã gọn gàng. Tôi chỉ có thể kiểm tra xem giá trị trả về có phải là không null trước khi thực hiện hành động thay thế hay không, trái ngược với việc ném một ngoại lệ từ hàm tạo. (Cá nhân tôi không thích ngoại lệ)

Giả sử, tôi có một hàm tạo trên một lớp có giá trị id. Hàm tạo sử dụng giá trị này để điền vào lớp từ cơ sở dữ liệu. Trong trường hợp một bản ghi với id được chỉ định không tồn tại, hàm tạo ném ra một RecordNotFoundException. Trong trường hợp này, tôi sẽ phải kèm theo việc xây dựng tất cả các lớp như vậy trong một khối try..catch.

Ngược lại với điều này, tôi có thể có một phương pháp nhà máy tĩnh trên các lớp đó sẽ trả về null nếu không tìm thấy bản ghi.

Phương pháp nào tốt hơn trong trường hợp này, phương thức khởi tạo hoặc phương thức nhà máy?

Trả lời

60

Từ trang 108 của Design Patterns: Elements of Reusable Object-Oriented Software by Gamma, Helm, Johnson, and Vlissides.

Sử dụng mô hình Nhà máy Phương pháp khi

  • một lớp không thể lường trước lớp của các đối tượng đó phải tạo
  • một lớp muốn lớp con của nó để xác định các đối tượng nó tạo ra các lớp học
  • phân bổ trách nhiệm cho một trong một số lớp con trợ giúp và bạn muốn bản địa hóa kiến ​​thức về phân lớp trợ giúp nào là đại biểu
+17

Phương thức factory tĩnh khác với kiểu thiết kế GoF - Pattern Method Factory. http://stackoverflow.com/questions/929021/what-are-static-factory-methods-in-java –

+0

Vui lòng không so sánh với mẫu phương thức Nhà máy của các mẫu thiết kế GoF. –

+80

điều này giải thích cho tôi không có gì – Sushant

23

Theo mặc định, các nhà thầu nên được ưu tiên, vì chúng đơn giản dễ hiểu và dễ viết hơn. Tuy nhiên, nếu bạn đặc biệt cần tách rời các thành phần xây dựng của một đối tượng khỏi ý nghĩa ngữ nghĩa của nó như được hiểu bởi mã máy khách, bạn nên sử dụng các nhà máy tốt hơn.

Sự khác biệt giữa các nhà xây dựng và nhà máy tương tự như, một biến và một con trỏ đến một biến. Có một mức độ khác biệt, đó là một bất lợi; nhưng cũng có một mức linh hoạt khác, đó là một lợi thế. Vì vậy, trong khi thực hiện một sự lựa chọn, bạn sẽ được tư vấn tốt để làm điều này chi phí so với phân tích lợi ích.

+13

Vì vậy, (kiểu TDD), bạn sẽ bắt đầu với các nhà thầu là cách đơn giản nhất để hoàn thành công việc. Và sau đó refactor đến các nhà máy một khi bạn bắt đầu nhận được mùi mã (như lặp đi lặp lại điều kiện logic xác định mà constructor để gọi)? – AndyM

+0

Tuyệt đối @ AndyM –

145

Hãy tự hỏi mình là gì và tại sao chúng tôi có chúng. Cả hai đều ở đó để tạo ra thể hiện của một đối tượng.

ElementarySchool school = new ElementarySchool(); 
ElementarySchool school = SchoolFactory.Construct(); // new ElementarySchool() inside 

Không có sự khác biệt nào cho đến thời điểm này. Bây giờ hãy tưởng tượng rằng chúng tôi có nhiều loại trường khác nhau và chúng tôi muốn chuyển từ việc sử dụng ElementarySchool sang HighSchool (có nguồn gốc từ một ElementarySchool hoặc thực hiện cùng một giao diện ISchool như ElementarySchool).Các thay đổi mã sẽ là:

HighSchool school = new HighSchool(); 
HighSchool school = SchoolFactory.Construct(); // new HighSchool() inside 

Trong trường hợp của một giao diện chúng ta sẽ có:

ISchool school = new HighSchool(); 
ISchool school = SchoolFactory.Construct(); // new HighSchool() inside 

Bây giờ nếu bạn có mã này ở nhiều nơi bạn có thể thấy rằng việc sử dụng phương pháp nhà máy có thể được khá rẻ vì một khi bạn thay đổi phương pháp nhà máy bạn đã làm (nếu chúng ta sử dụng ví dụ thứ hai với các giao diện).

Và đây là điểm khác biệt chính và lợi thế. Khi bạn bắt đầu giao dịch với một hệ thống phân cấp lớp phức tạp và bạn muốn tự động tạo một thể hiện của một lớp từ một hệ thống phân cấp như vậy, bạn sẽ nhận được mã sau đây. Các phương thức của nhà máy sau đó có thể lấy một tham số cho biết phương thức cụ thể nào để khởi tạo. Giả sử bạn có một lớp MyStudent và bạn cần phải khởi tạo đối tượng ISchool tương ứng để sinh viên của bạn là thành viên của trường đó.

ISchool school = SchoolFactory.ConstructForStudent(myStudent); 

Bây giờ bạn có một vị trí trong ứng dụng chứa logic nghiệp vụ xác định đối tượng ISchool nào để khởi tạo cho các đối tượng IStudent khác nhau.

Vì vậy - đối với các lớp đơn giản (giá trị đối tượng, vv) hàm tạo là tốt (bạn không muốn overengineer ứng dụng của bạn) nhưng đối với phương pháp nhà máy phân cấp lớp phức tạp là một cách ưa thích.

Bằng cách này, bạn tuân theo nguyên tắc thiết kế đầu tiên từ Chương trình gang of four book "cho giao diện, không phải là triển khai".

+1

Ngay cả khi bạn nghĩ rằng đó là một lớp học đơn giản, có một cơ hội ai đó cần phải mở rộng lớp học đơn giản của bạn, do đó, phương pháp nhà máy vẫn còn tốt hơn. Ví dụ. bạn có thể bắt đầu với ElementarySchool nhưng sau đó một người nào đó (bao gồm cả chính bạn) có thể mở rộng nó với PrivateElementarySchool và PublicElementarySchool. – jack

+5

đây phải là câu trả lời được chấp nhận – am05mhz

+1

@David, câu trả lời hay, nhưng bạn có thể mở rộng trên một ví dụ trong đó mỗi triển khai giao diện có thể yêu cầu các thông số khác nhau để xây dựng. Dưới đây là một ví dụ ngớ ngẩn: 'Bánh kẹp IFood = Bánh Sandwich mới (phô mai chz, Thịt thịt); 'và' Súp IFood = Canh mới (Canh dùng nước dùng, rau củ); 'Nhà máy và người xây dựng có thể giúp gì ở đây? –

11

Chỉ sử dụng nhà máy khi bạn cần kiểm soát thêm với việc tạo đối tượng, theo cách không thể thực hiện với các nhà thầu.

Các nhà máy có khả năng lưu bộ nhớ cache chẳng hạn.

Một cách khác để sử dụng các nhà máy là trong trường hợp bạn không biết loại bạn muốn xây dựng. Thông thường bạn thấy kiểu sử dụng này trong các kịch bản nhà máy plugin, nơi mỗi plugin phải lấy được từ một baseclass hoặc thực hiện một số loại giao diện. Nhà máy tạo ra các cá thể của các lớp bắt nguồn từ baseclass hoặc thực hiện giao diện.

54

Bạn cần đọc (nếu bạn có quyền truy cập) Effective Java 2Mục 1: Xem xét phương pháp nhà máy tĩnh thay vì nhà thầu.

tĩnh phương pháp nhà máy ưu điểm:

  1. Họ có những cái tên.
  2. Chúng không bắt buộc phải tạo đối tượng mới mỗi lần được gọi.
  3. Chúng có thể trả lại đối tượng của bất kỳ loại phụ nào thuộc loại trả về của chúng.
  4. Chúng giảm độ dài của việc tạo các thể hiện loại được tham số hóa.

phương pháp nhà máy tĩnh nhược điểm:

  1. Khi chỉ cung cấp phương pháp nhà máy tĩnh, các lớp học mà không nhà xây dựng công cộng hoặc bảo vệ không thể được subclassed.
  2. Chúng không dễ dàng phân biệt với các phương pháp tĩnh khác
+3

Điều này dường như với tôi thay vì một lỗi nghiêm trọng trong Java, sau đó là một vấn đề OOD chung. Có rất nhiều ngôn ngữ OO thậm chí không có * constructors, nhưng subclassing hoạt động tốt. –

+0

@cherouvim lý do tại sao hầu hết mã được viết bằng cách sử dụng Constructors nếu '(phương pháp nhà máy tốt hơn Constructors. (Item-1)) Hiệu quả java' – UnKnown

+0

Điểm tốt. Đó là Java cụ thể mặc dù. Một trường hợp có thể được thực hiện cho một tính năng ngôn ngữ mà làm cho phương pháp nhà máy phân biệt với các phương pháp tĩnh khác. – OCDev

6

Ví dụ cụ thể từ ứng dụng CAD/CAM.

Đường cắt sẽ được thực hiện bằng cách sử dụng hàm tạo. Nó là một loạt các đường và cung xác định một đường cắt. Trong khi hàng loạt các đường và cung có thể khác nhau và có các tọa độ khác nhau, nó dễ dàng được xử lý bằng cách chuyển danh sách vào một hàm tạo.

Hình dạng sẽ được thực hiện bằng cách sử dụng nhà máy. Bởi vì trong khi có một lớp hình dạng, mỗi hình dạng sẽ được thiết lập khác nhau tùy thuộc vào loại hình dạng của nó. Chúng tôi không biết hình dạng chúng ta sẽ khởi tạo cho đến khi người dùng thực hiện lựa chọn.

11

Trích dẫn từ "Java hiệu dụng", lần thứ 2, Mục 1: Xem xét phương pháp nhà máy tĩnh thay vì các nhà xây dựng, p. 5:

"Lưu ý rằng một phương thức tĩnh là không giống như mô hình Nhà máy Phương pháp từ Design Patterns [Gamma95, p 107.] Phương pháp nhà máy tĩnh được mô tả trong mặt hàng này không có tương đương trực tiếp trong. Mẫu thiết kế. "

3

Giả sử, tôi có một hàm tạo trên lớp có giá trị id. Hàm tạo sử dụng giá trị này để điền vào lớp từ cơ sở dữ liệu.

Quá trình này chắc chắn phải nằm ngoài một hàm tạo.

  1. Constructor không nên truy cập cơ sở dữ liệu.

  2. Nhiệm vụ và lý do cho một nhà xây dựng là để thành viên dữ liệu khởi tạolập lớp bất biến sử dụng giá trị được truyền vào constructor.

  3. Đối với mọi thứ khác một cách tiếp cận tốt hơn là sử dụng tĩnh phương pháp nhà máy hoặc trong trường hợp phức tạp hơn một nhà máy riêng hoặc builder lớp.

Some constructor guide lines from Microsoft:

làm việc tối thiểu trong các nhà xây dựng. Các nhà xây dựng không nên làm nhiều việc ngoài việc nắm bắt các tham số của hàm tạo. Chi phí của bất kỳ quá trình xử lý nào khác sẽ bị trì hoãn cho đến khi được yêu cầu.

Xem xét sử dụng một phương pháp nhà máy tĩnh thay vì một constructor nếu ngữ nghĩa của các hoạt động mong muốn không lập bản đồ trực tiếp đến việc xây dựng một trường hợp mới.

Các vấn đề liên quan