2008-10-11 29 views
41

Trong một ngôn ngữ mà cả hai đều có sẵn, bạn có muốn xem một hàm tạo cá thể hay một phương thức tĩnh trả về một cá thể không?Phương pháp nhà máy tĩnh so với các nhà xây dựng sơ thẩm (bình thường)?

Ví dụ, nếu bạn đang tạo một String từ một char[]:

  1. String.FromCharacters(chars);

  2. new String(chars);

+5

Đã thêm "phương thức" vào tiêu đề, nếu không, nó cho thấy lựa chọn là giữa một hàm tạo cá thể hoặc một hàm tạo tĩnh. (Văn bản rõ ràng, nhưng tiêu đề đã kích động một câu hỏi "Huh?" Nhất định trong tâm trí của tôi :) –

+0

@JonSkeet Chỉnh sửa của bạn đã được hoàn tác :) – gcampbell

+0

@gcampbell: Sẽ làm lại sau đó, xem xét câu hỏi rõ ràng * không * về các hàm tạo tĩnh ... –

Trả lời

50

Trong Effective Java, 2nd edition, Joshua Bloch chắc chắn đề xuất tên cũ. Có một vài lý do tôi có thể nhớ và không nghi ngờ một số lý do tôi không thể:

  • Bạn có thể đặt tên cho phương thức này là một tên có ý nghĩa. Nếu bạn có hai cách xây dựng một cá thể cả hai đều lấy một int, nhưng có ý nghĩa khác nhau cho int đó, bằng cách sử dụng một phương thức bình thường làm cho mã gọi có thể đọc được nhiều hơn.
  • Một hệ quả tất yếu của những người đầu tiên - bạn có thể có phương pháp nhà máy khác nhau với danh sách tham số cùng
  • Bạn có thể trả về null cho "sự thất bại tiềm năng dự kiến" trường hợp khi một constructor sẽ luôn hoặc trả lại một giá trị hoặc ném một ngoại lệ
  • Bạn có thể trở lại một kiểu khác so với khai báo (ví dụ như trả lại một lớp được thừa kế)
  • Bạn có thể sử dụng nó như một nhà máy, để có khả năng trả về một tham chiếu đến cùng một đối tượng nhiều lần

những nhược điểm:

  • Nó không phải là thành ngữ, hiện nay - các nhà phát triển đang được sử dụng nhiều hơn để nhìn thấy "mới"
  • Nếu bạn thấy "mới" bạn biết bạn đang nhận được một trường hợp mới (modulo các oddity I mentioned recently)
  • Bạn cần tạo các hàm tạo thích hợp có sẵn cho các lớp con
  • Trong C# 3, các lời gọi hàm tạo có thể thiết lập các trường/thuộc tính một cách nhỏ gọn với các biểu thức khởi tạo đối tượng; đối tượng địa lý không áp dụng cho các cuộc gọi phương thức tĩnh
+2

Đọc mục 2 trong Java hiệu quả có thể dễ dàng có được ấn tượng rằng Joshua Bloch có lợi cho việc sử dụng các phương thức nhà máy tĩnh làm lựa chọn mặc định. Nhưng tôi không nghĩ đó là trường hợp thực sự, hoặc ít nhất là vào năm 2002 khi anh ấy [phỏng vấn] (http://www.artima.com/intv/bloch14.html) với Bill Venners mà tôi trích dẫn trong câu trả lời của tôi tiếp tục xuống. –

+0

re. quan điểm của bạn về C#, tôi đã sử dụng mẫu này trong quá khứ; Xem câu trả lời của tôi ở đây cung cấp một workaround cho vấn đề khởi tạo nhỏ gọn (tốt, thay thế nó với một cái gì đó mà cũng là nhỏ gọn anyway!) Http://stackoverflow.com/a/10171659/705589 –

2

Static Method. Sau đó, bạn có thể trả lại giá trị rỗng, thay vì ném một ngoại lệ (trừ một loại tham chiếu)

2

Tôi thích hàm tạo mẫu, chỉ vì điều đó có ý nghĩa hơn đối với tôi và ít mơ hồ hơn với những gì bạn đang cố gắng thể hiện (ví dụ: nếu FromCharacters là một phương thức nhận một ký tự đơn). Chắc chắn chủ quan, mặc dù.

2

Cá nhân tôi thích nhìn thấy một hàm tạo thông thường, vì các contructors nên được sử dụng để xây dựng. Tuy nhiên, nếu có lý do chính đáng để không phải là hãy sử dụng một, nghĩa là nếu FromCharacters tuyên bố rõ ràng rằng nó không cấp phát bộ nhớ mới, nó sẽ là đáng giá. Chữ "mới" trong lời gọi có ý nghĩa.

7

Có một bài báo từ ICSE'07 đã nghiên cứu khả năng sử dụng của các nhà thầu so với các mẫu nhà máy.Trong khi tôi thích các mẫu nhà máy, nghiên cứu cho thấy rằng các nhà phát triển chậm hơn trong việc tìm ra phương pháp nhà máy chính xác.

http://www.cs.cmu.edu/~NatProg/papers/Ellis2007FactoryUsability.pdf

+0

Đó là một câu trả lời tốt, không may. Tôi sẵn sàng phân bổ mà không có từ khóa "mới", nhưng khả năng phát hiện khá quan trọng. Tôi ghét một người nào đó phải tự chế biến để tạo ra một đối tượng String lý thuyết vì họ không thấy một hàm tạo. –

+0

Tôi đồng ý, vấn đề làm thế nào để đảm bảo mọi người khám phá ra một tĩnh là một điều quan trọng. Tác giả thứ hai của bài báo đó hiện đang xây dựng một số công cụ cho rằng như là một phần của công việc tiến sĩ của mình, nó sẽ là thú vị để xem nơi này kết thúc. – Uri

+0

@Uri, Tất nhiên là chậm hơn ** hiện tại ** vì chưa có cơ quan tiêu chuẩn tạo ra quy ước đặt tên thích hợp cho các nhà thầu tĩnh. Tương phản với quy ước được biết đến rộng rãi của 'mới' trong các nhà xây dựng bình thường. – Pacerier

9

Nếu đối tượng của bạn là không thay đổi, bạn có thể sử dụng phương thức tĩnh để trở về đối tượng lưu trữ và tiết kiệm cho mình việc phân bổ và xử lý bộ nhớ.

19

Tôi viết một hàm tạo khi tạo cá thể không có tác dụng phụ, tức là khi điều duy nhất mà hàm tạo đang làm là khởi tạo các thuộc tính. Tôi viết một phương thức tĩnh (và làm cho hàm tạo riêng) nếu việc tạo cá thể làm một cái gì đó mà bạn thường không mong đợi một hàm tạo để làm.

Ví dụ:

public class Foo 
{ 
    private Foo() { } 

    private static List<Foo> FooList = new List<Foo>(); 
    public static Foo CreateFoo() 
    { 
     Foo f = new Foo(); 
     FooList.Add(f); 
     return f; 
    } 
} 

Bởi vì tôi tuân theo quy ước này, nếu tôi thấy

Foo f = Foo.CreateFoo(); 
Bar b = new Bar(); 

khi đọc mã của tôi, tôi có một tập hợp rất khác nhau của những kỳ vọng về những gì mỗi người trong số hai dòng đang làm. Mã đó không nói cho tôi biết điều gì tạo nên một Foo khác với việc tạo ra một Bar, nhưng nó nói với tôi rằng tôi cần phải nhìn.

+1

Điểm tốt về việc xử lý bất thường. Cá nhân, tôi không thích ý tưởng sử dụng một phương thức tĩnh thay cho hàm tạo mặc định. Nó lặp đi lặp lại và đi ngược dòng chảy của ngôn ngữ. Tôi muốn cấu trúc lại quá trình xử lý bất thường và sử dụng từ khóa mới, nếu có thể. –

+0

IMHO phải là câu trả lời đúng. –

+0

@Robert, Điều này không làm mất hiệu lực đối số "sử dụng tĩnh làm mặc định". Bạn vẫn có thể phân biệt một hàm tạo tĩnh từ một hàm tạo tĩnh đặc biệt (mà bạn cần * nhìn *) bằng cách sử dụng các quy ước đặt tên. Ví dụ. 'Foo.New() 'làm thay thế mặc định cho' new', và 'Foo.FromAbc()' vv cho các * * đặc biệt *. – Pacerier

2

Điều đó tùy thuộc. Đối với các ngôn ngữ trong đó sử dụng một hàm tạo thể hiện là "bình thường", tôi thường sử dụng một ngôn ngữ trừ khi tôi có lý do chính đáng để không. Điều này theo nguyên lý ít ngạc nhiên nhất.

Nhân tiện, bạn đã quên một trường hợp phổ biến khác: Một hàm tạo null/mặc định được ghép nối với phương thức khởi tạo.

+0

Vâng, tôi không nghĩ đến trường hợp đó. Tôi nghĩ rằng nó thua kém hơn hai được trình bày bởi vì nó cần đến các dòng mã. Tôi có thể chỉnh sửa các câu hỏi để bao gồm nó mặc dù. –

+0

@ejgottl, Bạn có ý nghĩa gì bởi "hàm tạo null được ghép nối với khởi tạo"? – Pacerier

+0

Một hàm tạo không có tham số và, có lẽ, chỉ cấp phát bộ nhớ rời khỏi đối tượng uninitialized. Được ghép nối với (các) phương thức khởi tạo. Nếu tôi nhớ chính xác, đây là cách các đối tượng Ruby được triển khai trong C. – ejgottl

1

Như Jon Skeet diễn giải Josh Bloch, có một số lý do tại sao một phương pháp nhà máy tĩnh là thích hợp hơn cho một nhà xây dựng trong nhiều trường hợp. Tôi sẽ nói rằng nếu lớp học là một lớp đơn giản không có thiết lập tốn kém hoặc sử dụng phức tạp, hãy ở lại với hàm tạo thành ngữ. Các JVM hiện đại giúp tạo đối tượng cực nhanh và rẻ. Nếu lớp có thể được phân lớp hoặc bạn có thể làm cho nó không thay đổi được (một lợi thế lớn cho lập trình đồng thời, mà sẽ chỉ quan trọng hơn), sau đó đi với phương pháp nhà máy.

Một mẹo khác. Không đặt tên cho phương thức nhà máy Foo.new* hoặc Foo.create*. Một phương pháp với những tên này nên luôn luôn trả về một thể hiện mới, và làm như vậy bỏ lỡ một trong những lợi thế lớn của phương pháp nhà máy. Một quy ước đặt tên tốt hơn là Foo.of* hoặc Foo.for*. Các Google Collections Library mới làm một công việc tuyệt vời này, imho.

+1

Bạn có thể mở rộng một chút về * tại sao * 'của *' và 'cho *' là các tên tốt hơn 'new *' hoặc 'create *'? Đặt tên đúng thứ là quan trọng đối với tôi, vì vậy tôi muốn tìm hiểu điều gì đó mới mẻ ở đây. – stakx

+0

@stakx: Nếu bạn sử dụng mới * hoặc tạo * bạn bị "buộc" để cung cấp một phiên bản mới, trong khi sử dụng các tên được đề xuất cho phép bạn sử dụng lại các tên hiện có. –

7

Gần đây tôi đã làm việc trên một API công cộng và tôi đã đau khổ vì lựa chọn phương pháp nhà máy tĩnh so với hàm tạo. Phương pháp nhà máy tĩnh chắc chắn có ý nghĩa trong một số trường hợp, nhưng trong những trường hợp khác, nó không rõ ràng và tôi không chắc chắn liệu sự nhất quán với phần còn lại của API có đủ lý do để đưa chúng vào các nhà xây dựng hay không.

Dù sao, tôi tình cờ gặp một quote from a Bill-Venners interview with Josh Bloch mà tôi thấy hữu ích:

Khi bạn đang viết một lớp, bạn có thể chạy xuống danh sách cuốn sách của tôi của lợi thế của nhà máy tĩnh hơn nhà xây dựng cộng đồng. Nếu bạn thấy rằng một số lượng đáng kể những lợi ích của đó thực sự áp dụng trong trường hợp của bạn, thì bạn nên đi với các nhà máy tĩnh . Nếu không, bạn nên đi với các nhà thầu.

Một số người thất vọng khi tìm thấy lời khuyên đó trong cuốn sách của tôi. Họ đọc nó và nói, "Bạn đã lập luận mạnh mẽ như vậy cho các nhà máy tĩnh công cộng mà chúng tôi chỉ nên sử dụng chúng theo mặc định." Tôi nghĩ rằng bất lợi thực sự duy nhất trong làm như vậy là nó là một chút disconcerting cho những người được sử dụng để sử dụng các nhà thầu để tạo ra các đối tượng của họ. Và tôi cho rằng nó cung cấp ít dấu hiệu trực quan hơn trong chương trình . (Bạn không thấy từ khóa mới.) Ngoài ra, nó còn khó khăn hơn để tìm các nhà máy tĩnh trong tài liệu, vì Javadoc nhóm tất cả các nhà xây dựng lại với nhau. Nhưng tôi xin nói rằng mọi người nên xem xét các nhà máy tĩnh trong thời gian và sử dụng chúng khi chúng là thích hợp.

Sau khi đọc báo giá đó và the study that Uri mentioned *, tôi cảm thấy có xu hướng sai về lợi ích của các nhà thầu trừ khi có lý do thuyết phục để làm khác. Tôi nghĩ rằng một phương pháp nhà máy tĩnh mà không có nguyên nhân tốt có lẽ chỉ là sự phức tạp không cần thiết và quá kỹ thuật. Mặc dù tôi cũng có thể thay đổi ý định của tôi một lần nữa vào ngày mai ...

* Thật không may là nghiên cứu này tập trung ít hơn vào phương pháp nhà máy tĩnh và nhiều hơn nữa trên mẫu nhà máy (nơi một đối tượng nhà máy riêng biệt tồn tại để tạo các phiên bản mới). không chắc chắn người ta có thể thực sự rút ra kết luận rằng phương pháp nhà máy tĩnh gây nhầm lẫn cho nhiều lập trình viên. Mặc dù nghiên cứu đã cho tôi ấn tượng rằng họ sẽ thường xuyên.

+0

+1 cho indepth- * ness *. Cần thêm upvotes. – Pacerier

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