Phương pháp "nhà máy tĩnh" là gì?
Phương pháp "nhà máy tĩnh" là gì?
Câu trả lời:
Chúng tôi tránh cung cấp quyền truy cập trực tiếp vào các kết nối cơ sở dữ liệu vì chúng chiếm nhiều tài nguyên. Vì vậy, chúng tôi sử dụng phương pháp nhà máy tĩnh getDbConnection
tạo kết nối nếu chúng tôi ở dưới giới hạn. Mặt khác, nó cố gắng cung cấp kết nối "dự phòng", không thành công nếu có ngoại lệ.
public class DbConnection{
private static final int MAX_CONNS = 100;
private static int totalConnections = 0;
private static Set<DbConnection> availableConnections = new HashSet<DbConnection>();
private DbConnection(){
// ...
totalConnections++;
}
public static DbConnection getDbConnection(){
if(totalConnections < MAX_CONNS){
return new DbConnection();
}else if(availableConnections.size() > 0){
DbConnection dbc = availableConnections.iterator().next();
availableConnections.remove(dbc);
return dbc;
}else {
throw new NoDbConnections();
}
}
public static void returnDbConnection(DbConnection dbc){
availableConnections.add(dbc);
//...
}
}
Mẫu phương thức tĩnh của nhà máy là một cách để đóng gói việc tạo đối tượng. Nếu không có một phương pháp nhà máy, bạn chỉ cần gọi của lớp constructor trực tiếp: Foo x = new Foo()
. Với mẫu này, thay vào đó bạn sẽ gọi phương thức xuất xưởng : Foo x = Foo.create()
. Các constructor được đánh dấu là private, vì vậy chúng không thể được gọi ngoại trừ từ bên trong lớp và phương thức Factory được đánh dấu static
để nó có thể được gọi mà không cần có đối tượng trước.
Có một vài lợi thế cho mẫu này. Một là nhà máy có thể chọn từ nhiều lớp con (hoặc người triển khai giao diện) và trả lại cái đó. Bằng cách này, người gọi có thể chỉ định hành vi mong muốn thông qua các tham số, mà không cần phải biết hoặc hiểu một hệ thống phân cấp lớp có khả năng phức tạp.
Một lợi thế khác là, như Matthew và James đã chỉ ra, kiểm soát truy cập vào một tài nguyên hạn chế như các kết nối. Đây là một cách để thực hiện các nhóm đối tượng có thể tái sử dụng - thay vì xây dựng, sử dụng và phá hủy một đối tượng, nếu việc xây dựng và phá hủy là các quy trình đắt tiền, có thể có ý nghĩa hơn khi xây dựng chúng một lần và tái chế chúng. Phương thức nhà máy có thể trả về một đối tượng được khởi tạo hiện tại, chưa sử dụng nếu nó có một đối tượng hoặc xây dựng một đối tượng nếu số lượng đối tượng nằm dưới ngưỡng thấp hơn hoặc ném ngoại lệ hoặc trả vềnull
nếu vượt quá ngưỡng trên.
Theo bài viết trên Wikipedia, nhiều phương thức xuất xưởng cũng cho phép các cách hiểu khác nhau về các loại đối số tương tự. Thông thường hàm tạo có cùng tên với lớp, có nghĩa là bạn chỉ có thể có một hàm tạo với một chữ ký đã cho . Các nhà máy không bị ràng buộc quá nhiều, có nghĩa là bạn có thể có hai phương thức khác nhau chấp nhận cùng loại đối số:
Coordinate c = Coordinate.createFromCartesian(double x, double y)
và
Coordinate c = Coordinate.createFromPolar(double distance, double angle)
Điều này cũng có thể được sử dụng để cải thiện khả năng đọc, như Rasmus lưu ý.
GHI CHÚ! "Các phương thức tĩnh là KHÔNG giống như các phương pháp Factory mô hình" (c) Effective Java, Joshua Bloch.
Phương thức Factory: "Xác định giao diện để tạo đối tượng, nhưng để các lớp thực hiện giao diện quyết định lớp nào sẽ khởi tạo. Phương thức Factory cho phép một lớp trì hoãn khởi tạo lớp cho các lớp con" (c) GoF.
"Phương thức tĩnh nhà máy chỉ đơn giản là một phương thức tĩnh trả về một thể hiện của một lớp." (c) Java hiệu quả, Joshua Bloch. Thông thường phương thức này là bên trong một lớp cụ thể.
Sự khác biệt:
Ý tưởng chính của phương thức tĩnh nhà máy là giành quyền kiểm soát đối với việc tạo đối tượng và ủy thác nó từ phương thức khởi tạo cho phương thức tĩnh. Quyết định của đối tượng được tạo giống như trong Tóm tắt Factory được thực hiện bên ngoài phương thức (trong trường hợp phổ biến, nhưng không phải luôn luôn). Trong khi ý tưởng chính (!) Của Phương thức Factory là ủy thác quyết định về trường hợp nào của lớp sẽ tạo bên trong Phương thức Factory. Ví dụ, triển khai Singleton cổ điển là trường hợp đặc biệt của phương pháp tĩnh nhà máy. Ví dụ về các phương pháp tĩnh nhà máy thường được sử dụng:
Khả năng đọc có thể được cải thiện bằng các phương pháp tĩnh nhà máy:
Đối chiếu
public class Foo{
public Foo(boolean withBar){
//...
}
}
//...
// What exactly does this mean?
Foo foo = new Foo(true);
// You have to lookup the documentation to be sure.
// Even if you remember that the boolean has something to do with a Bar
// you might not remember whether it specified withBar or withoutBar.
đến
public class Foo{
public static Foo createWithBar(){
//...
}
public static Foo createWithoutBar(){
//...
}
}
// ...
// This is much easier to read!
Foo foo = Foo.createWithBar();
private Foo(boolean withBar){/*..*/}
public static Foo createWithBar(){return new Foo(true);}
public static Foo createWithoutBar(){return new Foo(false);}
- có tên, không giống như constructor, có thể làm rõ mã.
- không cần tạo một đối tượng mới theo mỗi lần gọi - các đối tượng có thể được lưu trữ và sử dụng lại, nếu cần.
- có thể trả về một kiểu con của kiểu trả về của chúng - đặc biệt, có thể trả về một đối tượng mà lớp thực hiện không xác định đối với người gọi. Đây là một tính năng rất có giá trị và được sử dụng rộng rãi trong nhiều khung công tác sử dụng các giao diện làm kiểu trả về của các phương thức tĩnh của nhà máy.
Tất cả sôi sục để duy trì. Cách tốt nhất để đặt nó là bất cứ khi nào bạn sử dụngnew
từ khóa để tạo một đối tượng, bạn sẽ ghép mã mà bạn đang viết cho một triển khai.
Mẫu nhà máy cho phép bạn tách biệt cách bạn tạo một đối tượng khỏi những gì bạn làm với đối tượng. Khi bạn tạo tất cả các đối tượng của mình bằng cách sử dụng các hàm tạo, về cơ bản, bạn khó kết nối mã sử dụng đối tượng để thực hiện. Mã sử dụng đối tượng của bạn là "phụ thuộc" vào đối tượng đó. Điều này có vẻ không phải là một vấn đề lớn trên bề mặt, nhưng khi đối tượng thay đổi (nghĩ đến việc thay đổi chữ ký của nhà xây dựng, hoặc phân lớp đối tượng), bạn phải quay lại và sắp xếp lại mọi thứ ở mọi nơi.
Ngày nay, các nhà máy phần lớn đã bị gạt sang một bên ủng hộ việc sử dụng Dependency Injection vì họ yêu cầu rất nhiều mã nồi hơi, hóa ra hơi khó để tự duy trì. Dependency Injection về cơ bản tương đương với các nhà máy nhưng cho phép bạn chỉ định cách các đối tượng của bạn được nối với nhau theo cách khai báo (thông qua cấu hình hoặc chú thích).
Nếu hàm tạo của một lớp là riêng tư thì bạn không thể tạo một đối tượng cho lớp từ bên ngoài nó.
class Test{
int x, y;
private Test(){
.......
.......
}
}
Chúng ta không thể tạo một đối tượng cho lớp trên từ bên ngoài nó. Vì vậy, bạn không thể truy cập x, y từ bên ngoài lớp. Vậy thì việc sử dụng lớp học này là gì?
Dưới đây là câu trả lời: phương pháp NHÀ MÁY .
Thêm phương thức dưới đây trong lớp trên
public static Test getObject(){
return new Test();
}
Vì vậy, bây giờ bạn có thể tạo một đối tượng cho lớp này từ bên ngoài nó. Thích hướng này...
Test t = Test.getObject();
Do đó, một phương thức tĩnh trả về đối tượng của lớp bằng cách thực thi hàm tạo riêng của nó được gọi là phương thức FACTORY
.
Static Factory Method
với nhà xây dựng công cộng không?
Tôi nghĩ rằng tôi sẽ thêm một số ánh sáng cho bài viết này về những gì tôi biết. Chúng tôi đã sử dụng kỹ thuật này rộng rãi trong của chúng tôi recent android project
. Thay vì creating objects using new operator
bạn cũng có thể sử dụng static method
để khởi tạo một lớp. Mã danh sách:
//instantiating a class using constructor
Vinoth vin = new Vinoth();
//instantiating the class using static method
Class Vinoth{
private Vinoth(){
}
// factory method to instantiate the class
public static Vinoth getInstance(){
if(someCondition)
return new Vinoth();
}
}
Các phương thức tĩnh hỗ trợ tạo đối tượng có điều kiện : Mỗi lần bạn gọi hàm tạo, một đối tượng sẽ được tạo nhưng bạn có thể không muốn điều đó. giả sử bạn chỉ muốn kiểm tra một số điều kiện thì bạn muốn tạo một đối tượng mới. Bạn sẽ không tạo một phiên bản mới của Vinoth mỗi lần, trừ khi điều kiện của bạn được thỏa mãn.
Một ví dụ khác được lấy từ Java hiệu quả .
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
Phương thức này chuyển một giá trị nguyên thủy boolean thành tham chiếu đối tượng Boolean. Các Boolean.valueOf(boolean)
phương pháp minh họa chúng ta, nó không bao giờ tạo ra một đối tượng. Khả năng static factory methods
trả lại cùng một đối tượng từ lặp đi lặp lạiinvocations
cho phép các lớp duy trì sự kiểm soát chặt chẽ đối với những trường hợp tồn tại bất cứ lúc nào.
Static factory methods
là, không giống như constructors
, họ có thể trả object
về bất kỳ subtype
loại trả lại nào của họ. Một ứng dụng của tính linh hoạt này là API có thể trả về các đối tượng mà không cần công khai các lớp của chúng. Ẩn các lớp triển khai theo cách này dẫn đến một API rất nhỏ gọn.
Calendar.getInstance () là một ví dụ tuyệt vời cho ở trên, nó tạo ra tùy thuộc vào miền địa phương một BuddhistCalendar
, JapaneseImperialCalendar
hoặc bởi một mặc định Georgian
.
Một ví dụ khác mà tôi có thể nghĩ là Singleton pattern
, nơi bạn làm cho các nhà xây dựng của mình riêng tư tạo một getInstance
phương thức riêng mà bạn chắc chắn, luôn có sẵn một thể hiện.
public class Singleton{
//initailzed during class loading
private static final Singleton INSTANCE = new Singleton();
//to prevent creating another instance of Singleton
private Singleton(){}
public static Singleton getSingleton(){
return INSTANCE;
}
}
Một phương thức nhà máy là một phương thức trừu tượng hóa việc khởi tạo một đối tượng. Nói chung các nhà máy rất hữu ích khi bạn biết rằng bạn cần một phiên bản mới của một lớp thực hiện một số giao diện nhưng bạn không biết lớp triển khai.
Điều này rất hữu ích khi làm việc với hệ thống phân cấp của các lớp liên quan, một ví dụ điển hình cho việc này sẽ là bộ công cụ GUI. Bạn có thể chỉ cần gọi mã cứng đến các nhà xây dựng để triển khai cụ thể từng tiện ích nhưng nếu bạn muốn trao đổi một bộ công cụ cho một bộ công cụ khác, bạn sẽ có rất nhiều nơi để thay đổi. Bằng cách sử dụng một nhà máy, bạn giảm số lượng mã bạn cần thay đổi.
Một trong những lợi thế bắt nguồn từ Nhà máy tĩnh là API có thể trả về các đối tượng mà không cần công khai các lớp của chúng. Điều này dẫn đến API rất nhỏ gọn. Trong java, điều này đạt được bởi lớp Bộ sưu tập ẩn khoảng 32 lớp khiến API bộ sưu tập rất nhỏ gọn.
Một phương thức nhà máy tĩnh là tốt khi bạn muốn đảm bảo rằng chỉ một trường hợp duy nhất sẽ trả về lớp cụ thể được sử dụng.
Ví dụ, trong một lớp kết nối cơ sở dữ liệu, bạn có thể chỉ muốn có một lớp tạo kết nối cơ sở dữ liệu, để nếu bạn quyết định chuyển từ Mysql sang Oracle, bạn có thể thay đổi logic trong một lớp và phần còn lại của ứng dụng sẽ sử dụng kết nối mới.
Nếu bạn muốn triển khai cơ sở dữ liệu, thì điều đó cũng sẽ được thực hiện mà không ảnh hưởng đến phần còn lại của ứng dụng.
Nó bảo vệ phần còn lại của ứng dụng khỏi những thay đổi mà bạn có thể thực hiện cho nhà máy, đó là mục đích.
Lý do khiến nó tĩnh là nếu bạn muốn theo dõi một số tài nguyên hạn chế (số lượng kết nối ổ cắm hoặc tay cầm tệp) thì lớp này có thể theo dõi số lượng đã bị bỏ qua và trả lại, vì vậy bạn không làm cạn kiệt nguồn lực hạn chế.
Một trong những lợi thế của các phương thức nhà máy tĩnh với hàm tạo riêng (việc tạo đối tượng phải được hạn chế cho các lớp bên ngoài để đảm bảo các thể hiện không được tạo ra bên ngoài) là bạn có thể tạo các lớp được kiểm soát cá thể . Và các lớp được kiểm soát cá thể đảm bảo rằng không tồn tại hai trường hợp riêng biệt bằng nhau ( a.equals (b) khi và chỉ khi a == b ) trong khi chương trình của bạn chạy, điều đó có nghĩa là bạn có thể kiểm tra sự bằng nhau của các đối tượng với toán tử == thay vì phương thức bằng , theo java hiệu quả.
Khả năng của các phương thức nhà máy tĩnh trả về cùng một đối tượng từ các lệnh được lặp đi lặp lại cho phép các lớp duy trì sự kiểm soát chặt chẽ đối với những trường hợp tồn tại bất cứ lúc nào. Các lớp làm điều này được cho là kiểm soát cá thể. Có một số lý do để viết các lớp kiểm soát cá thể. Kiểm soát sơ thẩm cho phép một lớp đảm bảo rằng đó là một đơn (Mục 3) hoặc không đáng kể (Mục 4). Ngoài ra, nó cho phép một lớp bất biến (Mục 15) đảm bảo rằng không tồn tại hai trường hợp bằng nhau: a.equals (b) khi và chỉ khi a == b. Nếu một lớp thực hiện đảm bảo này, thì các máy khách của nó có thể sử dụng toán tử == thay vì phương thức bằng (Object), điều này có thể dẫn đến hiệu suất được cải thiện. Các loại Enum (Mục 30) cung cấp đảm bảo này.
Từ Java hiệu quả, Joshua Bloch (Mục 1, trang 6)
tĩnh
Một thành viên đã khai báo với từ khóa 'tĩnh'.
phương pháp nhà máy
Các phương thức tạo và trả về các đối tượng mới.
trong Java
Ngôn ngữ lập trình có liên quan đến ý nghĩa của 'tĩnh' nhưng không liên quan đến định nghĩa của 'nhà máy'.
Việc triển khai Java chứa các lớp tiện ích java.util.Arrays và java.util.Collections cả hai đều chứa các phương thức nhà máy tĩnh , các ví dụ về nó và cách sử dụng:
Arrays.asList("1","2","3")
Collections.synchronizedList(..), Collections.emptyList(), Collections.unmodifiableList(...)
(Chỉ một số ví dụ, có thể kiểm tra javadocs để biết ví dụ về các phương thức mor https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html )
Ngoài ra lớp java.lang.String có các phương thức tĩnh như vậy :
String.format(...), String.valueOf(..), String.copyValueOf(...)