2010-11-02 37 views
20

Trước hết hãy tha thứ cho tôi nếu một câu hỏi thực sự câm của tôi, tôi chỉ đang cố gắng học ngôn ngữ này với cốt lõi của nó. Tôi đang đọc Java hiệu quả và chương đầu tiên nói về phương pháp nhà máy tĩnh so với Constructors. Ưu và nhược điểm của họ. Vài điều mà rất khó hiểu đối với tôi là:phương pháp nhà máy tĩnh công cộng

  1. lớp của một đối tượng được trả về bởi phương thức tĩnh là không công khai - những gì chính xác nó nghĩa là gì?
  2. không giống như hàm tạo phương thức nhà máy tĩnh không bắt buộc phải tạo đối tượng mới mỗi khi được gọi - Điều này xảy ra như thế nào? Tôi gọi phương thức nhà máy chỉ để có được một đối tượng mới và chúng ta có đặt phương thức kiểm tra trong nhà máy để kiểm tra xem đối tượng đã tồn tại chưa?

Cảm ơn.

+2

+1 để tìm hiểu sâu về thực hành thiết kế phần mềm và đặt câu hỏi hay. –

+0

Cảm ơn Brian :) – t0mcat

+0

+1 vì đã hỏi TẠI SAO thay vì chỉ lập trình bằng cách viết. Thói quen của một coder tốt. – TreyE

Trả lời

11

lớp đối tượng được trả về bởi phương pháp nhà máy tĩnh là không công khai - chính xác nghĩa là gì?

Điều này có nghĩa là lớp thực tế của đối tượng được trả về bởi phương thức nhà máy tĩnh có thể là phân lớp của loại được khai báo và lớp con này không phải là công khai. Nó chỉ là một chi tiết thực hiện khác mà mã khách hàng không nên quan tâm.

không giống như hàm tạo phương thức nhà máy tĩnh không bắt buộc phải tạo đối tượng mới mỗi khi chúng được gọi - Điều này xảy ra như thế nào? Tôi gọi phương thức nhà máy chỉ để có được một đối tượng mới và chúng ta có đặt phương thức kiểm tra trong nhà máy để kiểm tra xem đối tượng đã tồn tại chưa?

Vâng, đó là một cách có thể thực hiện được. Nhưng thực sự, bất cứ điều gì là có thể.

+0

Hi Micheal, vì vậy nó phụ thuộc vào yêu cầu? Không có quy tắc cứng và nhanh nào mà các phương thức của nhà máy phải luôn luôn kiểm tra một cá thể đã có. – t0mcat

+0

@ t3ch: Đúng vậy. Vấn đề chỉ là bạn _can_ làm điều đó với các phương thức factory nếu nó có ích và những gì bạn muốn làm ... bạn không có tùy chọn đó với 'new'. – ColinD

+0

wow cảm ơn. Ít nhất bây giờ tôi biết nó sẽ hữu ích ở đâu. Singletons có thể được hiểu rõ hơn với cách tiếp cận này. – t0mcat

2

Khi bạn sử dụng từ khóa new thì bạn là nhà phát triển biết rằng JDK sẽ tạo ra một instace mới của đối tượng đó. Những gì tác giả đang nói, khi bạn sử dụng một phương thức tĩnh, nhà phát triển không còn biết liệu phương thức đó có tạo ra một cá thể mới hay có thể làm một cái gì khác. Một cái gì đó khác có thể được, tái sử dụng dữ liệu được lưu trữ, tạo nhóm đối tượng, tạo một triển khai riêng và trả về một lớp con của lớp.

+0

>> nếu phương pháp đang tạo một phiên bản mới hoặc có thể làm một việc khác. Amir, nếu phương thức tĩnh không tạo ra một cá thể mới hoặc trả về đối tượng mới, thì tại sao chúng ta cần một phương thức factory tĩnh? – t0mcat

+2

Bạn có thể không phải lúc nào cũng cần một trường hợp mới của một cái gì đó. Lấy ví dụ, các kết nối cơ sở dữ liệu: bạn làm trong java jdbc.newConnection(). Nhưng java không tạo ra một instance mới. Đầu tiên nó sẽ kiểm tra xem kết nối đã tồn tại chưa. Nếu không, nó sẽ có một phiên bản mới. Một ví dụ khác có thể là bạn muốn tạo một singleton. (Singletons có vấn đề riêng của họ) Có nghĩa là có một tốt đọc tại sao nên chỉ có một lần dụ của một lớp. Vì vậy, một lần nữa bạn sẽ làm cho constructor của bạn riêng tư và chỉ cho phép api của bạn được sử dụng thông qua các lớp tĩnh. –

+0

Ngoài ra, tôi không nói phương pháp nhà máy tĩnh là tốt trong anyway! Tôi chỉ nói đôi khi bạn cần nó, nhưng chỉ sử dụng nó nếu bạn có. Nó phải sạch hơn để sử dụng các nhà xây dựng hơn là một số phương pháp khó hiểu mà nhà phát triển phải tìm kiếm. –

1

lớp của một đối tượng được trả về bởi phương thức tĩnh là không công khai

thường một phương pháp nhà máy tĩnh sẽ trở lại hoặc là một đối tượng đánh máy như một giao diện (phổ biến nhất), hoặc đôi khi một số lớp cơ sở (ít chung). Trong cả hai trường hợp, bạn không biết lớp chính xác của đối tượng được trả về.

Lợi thế của việc này là nhận được một đối tượng có hành vi mà bạn biết mà không phải lo lắng về chi tiết lộn xộn của lớp mà nó khởi tạo.

không giống như nhà xây dựng phương pháp nhà máy tĩnh không cần phải tạo ra một đối tượng mới mỗi khi họ được gọi

Để hiểu điều này, hãy xem xét các trường hợp làm việc với một singleton. Bạn có thể gọi .getInstance() trên một số lớp nhà máy để có được cá thể singleton của một đối tượng nhất định.Thông thường, điều này làm là tạo một thể hiện của đối tượng nếu nó chưa tồn tại hoặc cung cấp cho bạn cá thể hiện tại nếu nó đã có. Trong cả hai trường hợp, bạn lấy lại một bản sao của đối tượng. Nhưng bạn không (và sẽ không) biết nếu singleton này đã được tạo ra, hoặc nếu một đã được xây dựng trước đó.

Ưu điểm của điều này là vòng đời của đối tượng và khi nó được tạo được quản lý cho bạn.

+0

Hi Trey, ví dụ singleton của bạn thực sự đã xóa bỏ sự nghi ngờ của tôi. Cảm ơn :) – t0mcat

0

Cả hai câu hỏi của bạn có thể được trả lời bằng cách xem một số mã sử dụng cả hai thuộc tính này của phương pháp nhà máy tĩnh. Tôi đề nghị xem số ImmutableList của Guava.

Lưu ý cách thức phương thức nhà máy không có arg of() luôn trả về cùng một cá thể (nó không tạo ra một cá thể mới mỗi lần). Nếu bạn nhìn kỹ, bạn cũng sẽ nhận thấy rằng phương thức nhà máy copyOf(Iterable) của nó thực sự trả về đối tượng được truyền cho nó nếu đối tượng đó là chính nó là ImmutableList. Cả hai điều này đều lợi dụng thực tế là một ImmutableList được đảm bảo không bao giờ thay đổi.

Cũng lưu ý cách các phương thức nhà máy khác nhau trả về các lớp con khác nhau, chẳng hạn như , SingletonImmutableListRegularImmutableList, mà không để lộ các loại đối tượng đó. Chữ ký của phương thức chỉ cho thấy rằng chúng trả lại ImmutableList và tất cả các lớp con của ImmutableList đều có chế độ hiển thị riêng tư (mặc định), khiến chúng ẩn với người dùng thư viện. Điều này cung cấp tất cả các ưu điểm của nhiều lớp triển khai mà không cần thêm bất kỳ sự phức tạp nào từ quan điểm của người dùng, vì chúng chỉ được phép xem ImmutableList dưới dạng một kiểu duy nhất.

Ngoài ImmutableList, hầu hết các lớp học tức thì trong Guava sử dụng phương pháp nhà máy tĩnh. Ổi cũng minh họa rất nhiều nguyên tắc được nêu trong Java hiệu quả (không đáng ngạc nhiên, vì nó được thiết kế bởi những nguyên tắc đó và với sự hướng dẫn của chính Josh Bloch), vì vậy bạn có thể thấy hữu ích khi nhìn vào nó nhiều hơn khi bạn ' đang làm việc thông qua cuốn sách.

+0

Cảm ơn Colin ví dụ. Đi qua nó. – t0mcat

4

Đầu tiên, bạn bè cho bạn lựa chọn trong ánh sáng Java: Sách của Bloch là một lớp lót tuyệt vời.

Để trả lời câu hỏi thứ 2 của bạn ('không giống như phương thức khởi tạo của nhà máy tĩnh không bắt buộc phải tạo đối tượng mới mỗi lần được gọi'), điều quan trọng là nhận ra rằng những gì Bloch đang nói ở đây là với một nhà máy tĩnh bạn có tùy chọn của một trong hai: trả về một đối tượng mới hoặc trả về một đối tượng đã tồn tại từ trước. Tất cả phụ thuộc vào những gì bạn muốn làm.

Ví dụ: giả sử bạn có loại giá trị thực sự đơn giản của loại Tiền. Phương pháp nhà máy tĩnh của bạn có thể sẽ trả về một cá thể mới - tức là một đối tượng mới có giá trị cụ thể cho Tiền. Vì vậy, như sau:

public class Money { 

    private Money(String amount) { ... } /* Note the 'private'-constructor */ 

    public static Money newInstance(String amount) { 
     return new Money(amount); 
    } 

} 

Nhưng giả sử bạn có một số đối tượng quản lý tài nguyên và bạn muốn đồng bộ hóa quyền truy cập vào tài nguyên đó thông qua một số lớp ResourceManager. Trong trường hợp đó, bạn có thể muốn phương thức factory tĩnh của bạn trả về cùng một cá thể của chính nó cho tất cả mọi người - buộc mọi người phải trải qua cùng một cá thể đó, sao cho 1 instance đó có thể kiểm soát quá trình. Điều này tuân theo mẫu đơn. Một cái gì đó như thế này:

public ResourceManager { 

    private final static ResourceManager me = new ResourceManager(); 

    private ResourceManager() { ... } /* Note the 'private'-constructor */ 

    public static ResourceManager getSingleton() { 
     return ResourceManager.me; 
    } 
} 

Phương pháp trên buộc người dùng của bạn chỉ có thể kiểm soát chính xác ai (và khi nào) có quyền truy cập vào bất kỳ thứ gì bạn đang quản lý.


Để trả lời câu hỏi đầu tiên của bạn, hãy xem xét này (phải thừa nhận là không phải là ví dụ tốt nhất, nó khá ad-hoc):

public class Money { 

    private Money(String amount) { ... } 


    public static Money getLocalizedMoney(MoneyType localizedMoneyType, String amount) { 
     switch(localizedMoneyType) { 
      case MoneyType.US: 
       return new Money_US(amount); 
      case MoneyType.BR: 
       return new Money_BR(amount); 
      default: 
       return new Money_US(amount); 
     } 
    } 
} 

public class Money_US extends Money { ... } 

public class Money_BR extends Money { ... } 

Lưu ý làm thế nào tôi bây giờ có thể làm điều này:

Money money = Money.getLocalizedMoney(user_selected_money_type); 
saveLocalizedMoney(money); 

Một lần nữa, một ví dụ thực sự giả tạo nhưng hy vọng nó sẽ giúp bạn nhìn thấy nhiều hơn hoặc ít hơn những gì Bloch đã nhận được tại thời điểm đó.

Các câu trả lời khác là tốt - tôi chỉ nghĩ rằng, là người mới bắt đầu, đôi khi nó giúp thấy một số mã thực tế.

+0

> chỉ nghĩ rằng, với tư cách là người mới bắt đầu, đôi khi nó giúp thấy một số mã thực sự. Cảm ơn vì đã xem xét sự thật này Bane. Các ví dụ của bạn thực sự hữu ích trong trường hợp bạn đang tạo một cá thể riêng và trả về cùng một cá thể mỗi lần cho ResourceManager. – t0mcat

+0

np - bất cứ khi nào học một khái niệm mới, tôi luôn đấu tranh với các câu trả lời trừu tượng/mơ hồ - mã khó kết hợp với một lời giải thích ngắn thường đi xa hơn nhiều với tôi. BTW, "Mục 3" trong cuốn sách của Bloch sẽ cung cấp cho bạn nhiều thứ hơn để nhai về cách tiếp cận singleton-factory. – Bane

+0

Cảm ơn Bane. mong cho nó. Các bạn sẽ thấy rất nhiều câu hỏi từ tôi :) – t0mcat

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