Tại sao tôi nên sử dụng một lớp nhà máy thay vì xây dựng đối tượng trực tiếp?


162

Tôi đã thấy lịch sử của một số dự án thư viện lớp Java # trên GitHub và CodePlex và tôi thấy xu hướng chuyển sang các lớp của nhà máy thay vì khởi tạo đối tượng trực tiếp.

Tại sao tôi nên sử dụng rộng rãi các lớp học nhà máy? Tôi có thư viện khá tốt, nơi các đối tượng được tạo theo cách lỗi thời - bằng cách gọi các nhà xây dựng công cộng của các lớp. Trong các cam kết cuối cùng, các tác giả đã nhanh chóng thay đổi tất cả các hàm tạo công khai của hàng ngàn lớp thành bên trong và cũng tạo ra một lớp nhà máy khổng lồ với hàng ngàn CreateXXXphương thức tĩnh chỉ trả về các đối tượng mới bằng cách gọi các hàm tạo bên trong của các lớp. API dự án bên ngoài bị hỏng, được thực hiện tốt.

Tại sao một sự thay đổi như vậy sẽ hữu ích? Điểm tái cấu trúc theo cách này là gì? Những lợi ích của việc thay thế các cuộc gọi đến các nhà xây dựng lớp công cộng bằng các cuộc gọi phương thức nhà máy tĩnh là gì?

Khi nào tôi nên sử dụng các nhà xây dựng công cộng, và khi nào tôi nên sử dụng các nhà máy?



1
Lớp / phương pháp vải là gì?
Doval

Câu trả lời:


56

Các lớp học tại nhà máy thường được triển khai vì chúng cho phép dự án tuân theo các nguyên tắc RẮN chặt chẽ hơn. Cụ thể, các nguyên tắc phân biệt giao diện và phụ thuộc đảo ngược.

Các nhà máy và giao diện cho phép linh hoạt lâu dài hơn rất nhiều. Nó cho phép thiết kế tách rời hơn - và do đó dễ kiểm tra hơn -. Dưới đây là danh sách không đầy đủ về lý do tại sao bạn có thể đi theo con đường này:

  • Nó cho phép bạn dễ dàng giới thiệu bộ chứa Inversion of Control (IoC)
  • Nó làm cho mã của bạn dễ kiểm tra hơn khi bạn có thể mô phỏng các giao diện
  • Nó cho phép bạn linh hoạt hơn rất nhiều khi đến lúc thay đổi ứng dụng (tức là bạn có thể tạo các triển khai mới mà không thay đổi mã phụ thuộc)

Hãy xem xét tình huống này.

Hội A (-> có nghĩa là phụ thuộc vào):

Class A -> Class B
Class A -> Class C
Class B -> Class D

Tôi muốn chuyển Lớp B sang Hội B, phụ thuộc vào Hội A. Với những phụ thuộc cụ thể này, tôi phải di chuyển hầu hết toàn bộ hệ thống phân cấp lớp của mình. Nếu tôi sử dụng giao diện, tôi có thể tránh được nhiều nỗi đau.

Hội A:

Class A -> Interface IB
Class A -> Interface IC
Class B -> Interface IB
Class C -> Interface IC
Class B -> Interface ID
Class D -> Interface ID

Bây giờ tôi có thể chuyển lớp B sang lắp ráp B mà không bị đau gì. Nó vẫn phụ thuộc vào các giao diện trong lắp ráp A.

Sử dụng bộ chứa IoC để giải quyết các phụ thuộc của bạn cho phép bạn linh hoạt hơn nữa. Không cần cập nhật mỗi cuộc gọi đến hàm tạo bất cứ khi nào bạn thay đổi các phụ thuộc của lớp.

Theo nguyên tắc phân tách giao diện và nguyên tắc đảo ngược phụ thuộc cho phép chúng tôi xây dựng các ứng dụng tách rời, rất linh hoạt. Khi bạn đã làm việc với một trong những loại ứng dụng này, bạn sẽ không bao giờ muốn quay lại sử dụng newtừ khóa.


40
Các nhà máy IMO là điều quan trọng nhất đối với RẮN. Bạn có thể làm RẮN chỉ tốt mà không cần nhà máy.
Euphoric

26
Một điều không bao giờ có ý nghĩa với tôi là, nếu bạn sử dụng các nhà máy để tạo ra các vật thể mới thì bạn phải tạo ra nhà máy ngay từ đầu. Vì vậy, chính xác những gì có được bạn? Có phải giả định rằng người khác sẽ cung cấp cho bạn nhà máy thay vì bạn tự khởi tạo nó, hoặc một cái gì khác? Điều này nên được đề cập trong câu trả lời, nếu không thì không rõ các nhà máy thực sự giải quyết vấn đề như thế nào.
Mehrdad

8
@ BЈовић - Ngoại trừ mỗi lần bạn thêm một triển khai mới, bây giờ bạn có thể mở nhà máy và sửa đổi nó để giải thích cho việc triển khai mới - vi phạm rõ ràng OCP.
Telastyn

6
@Telastyn Có, nhưng mã sử dụng các đối tượng được tạo không thay đổi. Điều đó quan trọng hơn sau đó là những thay đổi cho nhà máy.
BЈовић

8
Các nhà máy rất hữu ích trong các lĩnh vực nhất định mà câu trả lời được giải quyết. Chúng không thích hợp để sử dụng ở mọi nơi . Ví dụ: sử dụng các nhà máy để tạo chuỗi hoặc danh sách sẽ đưa nó đi quá xa. Ngay cả đối với UDT, chúng không phải lúc nào cũng cần thiết. Điều quan trọng là sử dụng một nhà máy khi việc thực hiện chính xác một giao diện cần được tách rời.

126

Giống như whatsisname đã nói, tôi tin rằng đây là trường hợp thiết kế phần mềm sùng bái hàng hóa . Các nhà máy, đặc biệt là loại trừu tượng, chỉ có thể sử dụng được khi mô-đun của bạn tạo nhiều phiên bản của một lớp và bạn muốn cung cấp cho người dùng khả năng mô-đun này để chỉ định loại sẽ tạo. Yêu cầu này thực sự khá hiếm, bởi vì hầu hết thời gian bạn chỉ cần một thể hiện và bạn chỉ có thể chuyển trực tiếp thể hiện đó thay vì tạo một nhà máy rõ ràng.

Vấn đề là, các nhà máy (và singletons) cực kỳ dễ thực hiện và vì vậy mọi người sử dụng chúng rất nhiều, ngay cả ở những nơi không cần thiết. Vì vậy, khi lập trình viên nghĩ "Tôi nên sử dụng mẫu thiết kế nào trong mã này?" Nhà máy là đầu tiên mà đến với tâm trí của mình.

Nhiều nhà máy được tạo ra bởi vì "Có thể, một ngày nào đó, tôi sẽ cần phải tạo ra những lớp khác nhau" trong tâm trí. Đó là một vi phạm rõ ràng của YAGNI .

Và các nhà máy trở nên lỗi thời khi bạn giới thiệu khung IoC, bởi vì IoC chỉ là một loại nhà máy. Và nhiều khung IoC có thể tạo ra các triển khai của các nhà máy cụ thể.

Ngoài ra, không có mẫu thiết kế nào nói rằng tạo các lớp tĩnh lớn với CreateXXXcác phương thức chỉ gọi các hàm tạo. Và nó đặc biệt không được gọi là Nhà máy (cũng không phải Nhà máy Trừu tượng).


6
Tôi đồng ý với hầu hết các điểm của bạn ngoại trừ "IoC là loại nhà máy" : Container IoC không phảinhà máy . Họ là một phương pháp thuận tiện để đạt được tiêm phụ thuộc. Vâng, một số có khả năng xây dựng các nhà máy tự động, nhưng bản thân chúng không phải là nhà máy và không nên đối xử như vậy. Tôi cũng tranh luận về điểm YAGNI. Nó rất hữu ích để có thể thay thế một bài kiểm tra kép trong bài kiểm tra đơn vị của bạn. Tái cấu trúc mọi thứ để cung cấp điều này sau khi thực tế là một nỗi đau ở mông . Lên kế hoạch trước và đừng rơi vào lý do "YAGNI"
AlexFoxGill

11
@AlexG - eh ... trong thực tế, khá nhiều container IoC hoạt động như các nhà máy.
Telastyn

8
@AlexG Trọng tâm chính của IoC là xây dựng các đối tượng cụ thể để truyền vào các đối tượng khác dựa trên cấu hình / quy ước. Điều này giống như sử dụng nhà máy. Và bạn không cần nhà máy để có thể tạo ra một bản thử nghiệm. Bạn chỉ cần khởi tạo và vượt qua giả trực tiếp. Giống như tôi đã nói trong đoạn đầu tiên. Các nhà máy chỉ hữu ích khi bạn muốn chuyển việc tạo một cá thể cho người dùng mô-đun, gọi nhà máy.
Euphoric

5
Có một sự khác biệt được thực hiện. Mẫu nhà máy được người tiêu dùng sử dụng để tạo các thực thể trong thời gian chạy chương trình. Một container IoC được sử dụng để tạo biểu đồ đối tượng của chương trình trong quá trình khởi động. Bạn có thể làm điều này bằng tay, container chỉ là một tiện lợi. Người tiêu dùng của một nhà máy không nên biết về container IoC.
AlexFoxGill

5
Re: "Và bạn không cần nhà máy để có thể tạo ra một bản thử nghiệm. Bạn chỉ cần khởi tạo và chuyển trực tiếp bản giả" - một lần nữa, các trường hợp khác nhau. Bạn sử dụng một nhà máy để yêu cầu một ví dụ - người tiêu dùng kiểm soát sự tương tác này. Cung cấp một thể hiện thông qua hàm tạo hoặc một phương thức không hoạt động, đó là một kịch bản khác.
AlexFoxGill

79

Phiên bản mẫu của Factory xuất phát từ niềm tin gần như giáo điều của các lập trình viên trong các ngôn ngữ "kiểu C" (C / C ++, C #, Java) sử dụng từ khóa "mới" là xấu và nên tránh bằng mọi giá (hoặc tại ít tập trung nhất). Đến lượt nó, xuất phát từ một cách giải thích cực kỳ nghiêm ngặt về Nguyên tắc Trách nhiệm duy nhất ("S" của RẮN), và cả Nguyên tắc đảo ngược phụ thuộc ("D"). Nói một cách đơn giản, SRP nói rằng lý tưởng là một đối tượng mã nên có một "lý do để thay đổi" và chỉ một lý do; rằng "lý do để thay đổi" là mục đích trung tâm của đối tượng đó, "trách nhiệm" của nó trong cơ sở mã và bất kỳ điều gì khác yêu cầu thay đổi mã không nên yêu cầu mở tệp lớp đó. DIP thậm chí còn đơn giản hơn; một đối tượng mã không bao giờ nên phụ thuộc vào một đối tượng cụ thể khác,

Trong trường hợp, bằng cách sử dụng "mới" và một nhà xây dựng công cộng, bạn đang ghép mã gọi với một phương thức xây dựng cụ thể của một lớp bê tông cụ thể. Mã của bạn bây giờ phải biết rằng một lớp MyFooObject tồn tại và có một hàm tạo có một chuỗi và một int. Nếu nhà xây dựng đó cần thêm thông tin, tất cả các cách sử dụng của nhà xây dựng phải được cập nhật để chuyển thông tin đó bao gồm thông tin bạn đang viết bây giờ, và do đó họ bắt buộc phải có một cái gì đó hợp lệ để truyền vào, và vì vậy họ phải có nó hoặc được thay đổi để có được nó (thêm nhiều trách nhiệm hơn cho các đối tượng tiêu thụ). Ngoài ra, nếu MyFooObject được thay thế trong cơ sở mã bởi BetterFooObject, tất cả các cách sử dụng của lớp cũ phải thay đổi để xây dựng đối tượng mới thay vì đối tượng cũ.

Vì vậy, thay vào đó, tất cả người tiêu dùng MyFooObject nên phụ thuộc trực tiếp vào "IFooObject", định nghĩa hành vi triển khai các lớp bao gồm MyFooObject. Bây giờ, người tiêu dùng IFooObject không thể chỉ xây dựng IFooObject (mà không có kiến ​​thức rằng một lớp cụ thể cụ thể là IFooObject, mà họ không cần), vì vậy thay vào đó họ phải được cung cấp một thể hiện của lớp hoặc phương thức triển khai IFooObject từ bên ngoài, bởi một đối tượng khác có trách nhiệm biết cách tạo IFooObject chính xác cho trường hợp, theo cách nói của chúng tôi thường được gọi là Nhà máy.

Bây giờ, đây là nơi lý thuyết đáp ứng thực tế; một đối tượng không bao giờ có thể bị đóng đối với tất cả các loại thay đổi mọi lúc. Trường hợp cụ thể, IFooObject hiện là một đối tượng mã bổ sung trong cơ sở mã, phải thay đổi bất cứ khi nào giao diện được yêu cầu bởi người tiêu dùng hoặc việc triển khai IFooObject thay đổi. Điều đó giới thiệu một mức độ phức tạp mới liên quan đến việc thay đổi cách các đối tượng tương tác với nhau trong sự trừu tượng hóa này. Ngoài ra, người tiêu dùng vẫn sẽ phải thay đổi, và sâu sắc hơn, nếu bản thân giao diện được thay thế bằng một giao diện mới.

Một lập trình viên giỏi biết cách cân bằng YAGNI ("Bạn không cần nó") với RẮN, bằng cách phân tích thiết kế và tìm những nơi rất có khả năng phải thay đổi theo một cách cụ thể và tái cấu trúc chúng để trở nên khoan dung hơn rằng loại thay đổi, bởi vì trong trường hợp đó "bạn sẽ cần đến nó".


21
Yêu câu trả lời này, đặc biệt sau khi đọc tất cả những người khác. Tôi có thể thêm gần như tất cả các lập trình viên mới (tốt) quá nhiều giáo điều về các nguyên tắc bởi thực tế đơn giản họ thực sự muốn giỏi nhưng chưa học được giá trị của việc giữ mọi thứ đơn giản và không quá mức cần thiết.
jean

1
Một vấn đề khác với các nhà xây dựng công cộng là không có cách nào tốt để một lớp Foochỉ định một nhà xây dựng công cộng có thể sử dụng được để tạo các Foothể hiện hoặc tạo các loại khác trong cùng một gói / lắp ráp , nhưng không thể sử dụng để tạo các loại có nguồn gốc ở nơi khác. Tôi không biết bất kỳ lý do đặc biệt hấp dẫn nào mà một ngôn ngữ / khung không thể định nghĩa các hàm tạo riêng biệt để sử dụng trong các newbiểu thức, so với lời gọi từ các hàm tạo kiểu con, nhưng tôi không biết bất kỳ ngôn ngữ nào tạo ra sự khác biệt đó.
supercat

1
Một nhà xây dựng được bảo vệ và / hoặc nội bộ sẽ là một tín hiệu như vậy; hàm tạo này sẽ chỉ khả dụng để sử dụng mã cho dù trong một lớp con hoặc trong cùng một cụm. C # không có kết hợp từ khóa cho "được bảo vệ và bên trong" nghĩa là chỉ các kiểu con trong hội đồng có thể sử dụng nó, nhưng MSIL có một định danh phạm vi cho loại khả năng hiển thị đó để có thể hiểu được thông số C # để cung cấp cách sử dụng nó . Nhưng, điều này thực sự không liên quan nhiều đến việc sử dụng các nhà máy (trừ khi bạn sử dụng hạn chế về tầm nhìn để thực thi việc sử dụng của nhà máy).
KeithS

2
Câu trả lời hoàn hảo. Đúng điểm với phần 'lý thuyết đáp ứng thực tế'. Chỉ cần nghĩ rằng có bao nhiêu hàng ngàn nhà phát triển và thời gian của con người dành thời gian ca ngợi hàng hóa, biện minh, thực hiện, sử dụng chúng để rơi vào tình huống tương tự như bạn mô tả, chỉ là điên rồ. Theo YAGNI, Ive chưa bao giờ xác định được nhu cầu triển khai nhà máy
Breno Salgado

Tôi đang lập trình trên một cơ sở mã bởi vì việc triển khai OOP không cho phép quá tải hàm tạo, việc sử dụng các hàm tạo công cộng bị cấm một cách hiệu quả. Đây đã là một vấn đề nhỏ trong các ngôn ngữ cho phép nó. Thích tạo nhiệt độ. Cả Fahrenheit và Celsius đều là phao. Tuy nhiên, bạn có thể đóng hộp, sau đó giải quyết vấn đề.
jgmjgm

33

Các nhà xây dựng là tốt khi chúng chứa mã ngắn, đơn giản.

Khi khởi tạo trở nên nhiều hơn việc gán một vài biến cho các trường, một nhà máy có ý nghĩa. Dưới đây là một số lợi ích:

  • Mã dài, phức tạp có ý nghĩa hơn trong một lớp chuyên dụng (một nhà máy). Nếu cùng một mã được đặt trong một hàm tạo gọi một loạt các phương thức tĩnh, thì điều này sẽ gây ô nhiễm cho lớp chính.

  • Trong một số ngôn ngữ và một số trường hợp, ném ngoại lệ vào các nhà xây dựng là một ý tưởng thực sự tồi tệ , vì nó có thể gây ra lỗi.

  • Khi bạn gọi một hàm tạo, bạn, người gọi, cần biết chính xác loại thể hiện bạn muốn tạo. Điều này không phải lúc nào cũng đúng (vì Feeder, tôi chỉ cần xây dựng Animalđể nuôi nó; tôi không quan tâm nếu đó là a Doghay a Cat).


2
Các lựa chọn không chỉ là "nhà máy" hay "nhà xây dựng." A Feedercó thể không sử dụng, và thay vào đó gọi phương thức Kennelcủa đối tượng đó getHungryAnimal.
DougM

4
+1 Tôi thấy rằng việc tuân thủ quy tắc hoàn toàn không có logic trong một nhà xây dựng không phải là một ý tưởng tồi. Một constructor chỉ nên được sử dụng để thiết lập trạng thái ban đầu của đối tượng bằng cách gán các giá trị đối số của nó cho các biến thể hiện. Nếu bất cứ điều gì phức tạp hơn là cần thiết, ít nhất hãy tạo một phương thức nhà máy (lớp) để xây dựng thể hiện.
KaptajnKold

Đây là câu trả lời thỏa mãn duy nhất tôi thấy ở đây, giúp tôi không phải tự viết. Các câu trả lời khác chỉ giải quyết các khái niệm trừu tượng.
TheCatWhisperer

Nhưng đối số này cũng có thể được giữ đúng Builder Pattern. Phải không?
soufrk

Quy tắc xây dựng
Breno Salgado

10

Nếu bạn làm việc với các giao diện thì bạn có thể vẫn độc lập với việc thực hiện thực tế. Một nhà máy có thể được cấu hình (thông qua các thuộc tính, tham số hoặc một số phương thức khác) để khởi tạo một trong số các triển khai khác nhau.

Một ví dụ đơn giản: bạn muốn giao tiếp với một thiết bị nhưng bạn không biết liệu nó sẽ thông qua Ethernet, COM hay USB. Bạn xác định một giao diện và 3 triển khai. Sau đó, bạn có thể chọn phương thức nào bạn muốn và nhà máy sẽ cung cấp cho bạn cách thực hiện phù hợp.

Sử dụng nó thường xuyên ...


5
Tôi sẽ nói thêm rằng thật tuyệt khi sử dụng khi có nhiều triển khai của một giao diện mã cuộc gọi không hoặc không nên chọn cái nào. Nhưng khi một phương thức nhà máy chỉ đơn giản là một trình bao bọc tĩnh xung quanh một hàm tạo duy nhất như trong câu hỏi, đó là mô hình chống. Phải nhiều triển khai để chọn hoặc nhà máy đang cản trở và thêm sự phức tạp không cần thiết.

Bây giờ bạn đã có thêm tính linh hoạt và về lý thuyết, ứng dụng của bạn có thể sử dụng Ethernet, COM, USB và nối tiếp, đã sẵn sàng cho Fireloop hoặc bất cứ điều gì, theo lý thuyết. Trong thực tế, ứng dụng của bạn sẽ chỉ giao tiếp qua Ethernet .... bao giờ hết.
Pieter B

7

Đó là một triệu chứng của một giới hạn trong các hệ thống mô-đun của Java / C #.

Về nguyên tắc, không có lý do gì bạn không thể trao đổi một triển khai của một lớp cho một lớp khác với cùng chữ ký của hàm tạo và phương thức. Có những ngôn ngữ cho phép điều này. Tuy nhiên, Java và C # nhấn mạnh rằng mỗi lớp có một mã định danh duy nhất (tên đủ điều kiện) và mã máy khách kết thúc với sự phụ thuộc được mã hóa cứng vào nó.

Bạn có thể sắp xếp xung quanh vấn đề này bằng cách thay đổi hệ thống tệp và các tùy chọn trình biên dịch để com.example.Fooánh xạ tới một tệp khác, nhưng điều này thật đáng ngạc nhiên và không trực quan. Ngay cả khi bạn làm như vậy, mã của bạn vẫn được gắn với chỉ một lần thực hiện của lớp. Tức là Nếu bạn viết một lớp Foophụ thuộc vào một lớp MySet, bạn có thể chọn triển khai MySetvào thời gian biên dịch nhưng bạn vẫn không thể khởi tạo Foos bằng hai cách triển khai khác nhau MySet.

Quyết định thiết kế không may này buộc mọi người sử dụng interfacemột cách không cần thiết để chứng minh mã của họ trong tương lai chống lại khả năng sau này họ sẽ cần một triển khai khác của một cái gì đó, hoặc để tạo điều kiện cho thử nghiệm đơn vị. Điều này không phải lúc nào cũng khả thi; nếu bạn có bất kỳ phương thức nào xem xét các trường riêng của hai trường hợp của lớp, sẽ không thể thực hiện chúng trong một giao diện. Đó là lý do tại sao, ví dụ, bạn không thấy uniontrong Setgiao diện của Java . Tuy nhiên, bên ngoài các kiểu số và bộ sưu tập, các phương thức nhị phân không phổ biến, vì vậy bạn thường có thể thoát khỏi nó.

Tất nhiên, nếu bạn gọi new Foo(...)bạn vẫn có sự phụ thuộc vào lớp , vì vậy bạn cần một nhà máy nếu bạn muốn một lớp có thể khởi tạo giao diện trực tiếp. Tuy nhiên, thường là một ý tưởng tốt hơn để chấp nhận thể hiện trong hàm tạo và để người khác quyết định sử dụng triển khai nào.

Tùy thuộc vào bạn để quyết định xem có đáng để làm nổi bật cơ sở mã của bạn với các giao diện và nhà máy hay không. Một mặt, nếu lớp được đề cập là nội bộ đối với cơ sở mã của bạn, thì việc cấu trúc lại mã để nó sử dụng một lớp khác hoặc một giao diện trong tương lai là không đáng kể; bạn có thể gọi YAGNI và tái cấu trúc sau nếu tình huống phát sinh. Nhưng nếu lớp là một phần của API công khai của thư viện bạn đã xuất bản, bạn không có tùy chọn sửa mã máy khách. Nếu bạn không sử dụng interfacevà sau này cần nhiều triển khai, bạn sẽ bị mắc kẹt giữa một tảng đá và một nơi khó khăn.


2
Tôi ước Java và các công cụ phái sinh như .NET có một cú pháp đặc biệt cho một lớp tạo các cá thể của chính nó và nếu không thì newđơn giản là đường cú pháp để gọi một phương thức tĩnh có tên đặc biệt (sẽ được tạo tự động nếu một loại có "hàm tạo công khai "Nhưng không bao gồm rõ ràng phương pháp). IMHO, nếu mã chỉ muốn một thứ mặc định nhàm chán thực hiện List, thì giao diện có thể cung cấp cho nó mà không cần khách hàng phải biết về bất kỳ triển khai cụ thể nào (ví dụ ArrayList).
supercat

2

Theo tôi, họ chỉ sử dụng Nhà máy đơn giản, không phải là một mẫu thiết kế phù hợp và không nên nhầm lẫn với Nhà máy trừu tượng hoặc Phương pháp nhà máy.

Và vì họ đã tạo ra một "lớp vải khổng lồ với hàng ngàn phương thức tĩnh CreatXXX", âm thanh đó có vẻ chống mẫu (có thể là một lớp Thần?).

Tôi nghĩ rằng Simple Factory và các phương thức tạo tĩnh (không yêu cầu lớp bên ngoài), có thể hữu ích trong một số trường hợp. Ví dụ, khi việc xây dựng một đối tượng đòi hỏi các bước khác nhau như kích thích các đối tượng khác (ví dụ: ủng hộ thành phần).

Tôi thậm chí sẽ không gọi đó là Nhà máy, mà chỉ là một loạt các phương thức được gói gọn trong một số lớp ngẫu nhiên với hậu tố "Nhà máy".


1
Nhà máy đơn giản có vị trí của nó. Hãy tưởng tượng một thực thể có hai tham số hàm tạo int xIFooService fooService. Bạn không muốn đi khắp fooServicenơi, vì vậy bạn tạo ra một nhà máy bằng một phương pháp Create(int x)và tiêm dịch vụ bên trong nhà máy.
AlexFoxGill

4
@AlexG Và sau đó, bạn phải đi khắp IFactorynơi thay vì IFooService.
Euphoric

3
Tôi đồng ý với Euphoric; theo kinh nghiệm của tôi, các đối tượng được đưa vào biểu đồ từ trên xuống có xu hướng thuộc loại mà tất cả các đối tượng cấp thấp hơn cần, và vì vậy việc chuyển IFooService xung quanh không phải là vấn đề lớn. Thay thế một sự trừu tượng hóa bằng một sự trừu tượng hóa khác không thực hiện được bất cứ điều gì ngoài việc làm xáo trộn thêm cơ sở mã.
KeithS

điều này có vẻ hoàn toàn không liên quan đến câu hỏi, "Tại sao tôi nên sử dụng một lớp nhà máy thay vì xây dựng đối tượng trực tiếp? Khi nào tôi nên sử dụng các nhà xây dựng công cộng, và khi nào tôi nên sử dụng các nhà máy?" Xem cách trả lời
gnat

1
Đó chỉ là tiêu đề của câu hỏi, tôi nghĩ bạn đã bỏ lỡ phần còn lại của nó. Xem điểm cuối cùng của liên kết được cung cấp;).
FranMowinckel

1

Là người dùng của thư viện, nếu thư viện có các phương thức xuất xưởng, thì bạn nên sử dụng chúng. Bạn sẽ cho rằng phương thức xuất xưởng mang lại cho tác giả của thư viện sự linh hoạt để thực hiện các thay đổi nhất định mà không ảnh hưởng đến mã của bạn. Ví dụ, họ có thể trả về một thể hiện của một số lớp con trong một phương thức nhà máy, không hoạt động với một hàm tạo đơn giản.

Là người tạo ra một thư viện, bạn sẽ sử dụng các phương thức xuất xưởng nếu bạn muốn tự mình sử dụng tính linh hoạt đó.

Trong trường hợp bạn mô tả, bạn dường như có ấn tượng rằng việc thay thế các hàm tạo bằng các phương thức xuất xưởng là vô nghĩa. Đó chắc chắn là một nỗi đau cho tất cả mọi người liên quan; một thư viện không nên xóa bất cứ thứ gì khỏi API của nó mà không có lý do chính đáng. Vì vậy, nếu tôi đã thêm các phương thức xuất xưởng, tôi sẽ để các hàm tạo hiện có sẵn, có lẽ không dùng nữa, cho đến khi một phương thức xuất xưởng không gọi hàm tạo đó nữa và mã sử dụng hàm tạo đơn giản hoạt động kém hơn bình thường. Ấn tượng của bạn rất có thể đúng.


Cũng lưu ý; Nếu nhà phát triển cần cung cấp một lớp dẫn xuất với chức năng bổ sung (thuộc tính bổ sung, khởi tạo), nhà phát triển có thể làm điều đó. (giả sử rằng các phương pháp nhà máy là quá mức). Tác giả API cũng có thể cung cấp một công việc cho các nhu cầu đặc biệt của khách hàng.
Eric Schneider

-4

Điều này dường như đã lỗi thời trong thời đại của Scala và lập trình chức năng. Một nền tảng vững chắc của các chức năng thay thế một lớp gazillion.

Cũng cần lưu ý rằng gấp đôi của Java {{không hoạt động nữa khi sử dụng một nhà máy tức là

someFunction(new someObject() {{
    setSomeParam(...);
    etc..
}})

Điều này có thể cho phép bạn tạo một lớp ẩn danh và tùy chỉnh nó.

Trong tình trạng không gian thời gian, yếu tố thời gian bị thu hẹp rất nhiều nhờ CPU nhanh mà lập trình chức năng cho phép thu hẹp không gian tức là kích thước mã hiện đang thực tế.


2
điều này trông giống như một nhận xét tiếp tuyến (xem Cách trả lời ) và dường như nó không cung cấp bất cứ điều gì đáng kể so với các điểm được thực hiện và giải thích trong 9 câu trả lời trước
gnat
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.