Co to jest metoda „fabryki statycznej”?
Co to jest metoda „fabryki statycznej”?
Odpowiedzi:
Unikamy zapewniania bezpośredniego dostępu do połączeń z bazą danych, ponieważ wymagają one dużych zasobów. Dlatego używamy statycznej metody fabrycznej, getDbConnection
która tworzy połączenie, jeśli nie osiągniemy limitu. W przeciwnym razie próbuje zapewnić połączenie „zapasowe”, aw przypadku wyjątku nie powiodło się.
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);
//...
}
}
Statyczna metoda wytwórcza jest sposobem tworzenia obiektów hermetyzacji. Bez metody fabryki, byś po prostu zadzwonić na klasę za konstruktora bezpośrednio: Foo x = new Foo()
. Z tego wzoru, byś zamiast wywołać metodę fabryczną: Foo x = Foo.create()
. Konstruktory są oznaczone jako prywatne, więc nie można ich wywoływać inaczej niż z wnętrza klasy, a metoda fabryki jest oznaczona static
tak, że można ją wywoływać bez uprzedniego posiadania obiektu.
Ten wzór ma kilka zalet. Jednym z nich jest to, że fabryka może wybrać jedną z wielu podklas (lub implementatorów interfejsu) i zwrócić to. W ten sposób osoba dzwoniąca może określić pożądane zachowanie za pomocą parametrów, bez konieczności znajomości lub zrozumienia potencjalnie złożonej hierarchii klas.
Kolejną zaletą jest, jak zauważyli Matthew i James, kontrolowanie dostępu do ograniczonych zasobów, takich jak połączenia. W ten sposób można wdrożyć pule obiektów wielokrotnego użytku - zamiast budować, używać i burzyć obiekt, jeśli budowa i zniszczenie są kosztownymi procesami, sensowniejsze może być ich zbudowanie i ponowne przetworzenie. Metoda fabryczna może zwrócić istniejący, nieużywany obiekt instancji, jeśli ma taki obiekt, lub zbudować go, jeśli liczba obiektów jest poniżej pewnego dolnego progu, lub zgłosić wyjątek lub zwrócić, null
jeśli jest powyżej górnego progu.
Zgodnie z artykułem na Wikipedii wiele metod fabrycznych pozwala również na różne interpretacje podobnych typów argumentów. Zwykle konstruktor ma taką samą nazwę jak klasa, co oznacza, że możesz mieć tylko jednego konstruktora o danej sygnaturze . Fabryki nie są tak ograniczone, co oznacza, że możesz mieć dwie różne metody, które akceptują te same typy argumentów:
Coordinate c = Coordinate.createFromCartesian(double x, double y)
i
Coordinate c = Coordinate.createFromPolar(double distance, double angle)
Można to również wykorzystać do poprawy czytelności, jak zauważa Rasmus.
UWAGA! „ Statyczna metoda fabryczna NIE jest taka sama jak wzorzec metody fabrycznej ” (c) Effective Java, Joshua Bloch.
Metoda fabryczna: „Zdefiniuj interfejs do tworzenia obiektu, ale pozwól klasom, które implementują interfejs, zdecydować, którą klasę utworzyć. Metoda fabryczna umożliwia odłożenie instancji klasy na podklasy” (c) GoF.
„Statyczna metoda fabryczna to po prostu metoda statyczna, która zwraca instancję klasy.” (c) Skuteczna Java, Joshua Bloch. Zwykle ta metoda znajduje się w określonej klasie.
Różnica:
Kluczową ideą statycznej metody fabrycznej jest przejęcie kontroli nad tworzeniem obiektów i przekazanie jej z konstruktora na metodę statyczną. Decyzja o obiekcie, który ma zostać utworzony, jest taka jak w Abstract Factory podjęta poza metodą (w powszechnym przypadku, ale nie zawsze). Podczas gdy kluczowym (!) Pomysłem Metody Fabrycznej jest delegowanie decyzji, która instancja klasy ma zostać utworzona w ramach Metody Fabrycznej. Np. Klasyczna implementacja Singleton jest szczególnym przypadkiem statycznej metody fabrycznej. Przykład powszechnie stosowanych statycznych metod fabrycznych:
Czytelność można poprawić za pomocą statycznych metod fabrycznych:
Porównać
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.
do
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);}
- mają nazwy, w przeciwieństwie do konstruktorów, które mogą wyjaśniać kod.
- nie trzeba tworzyć nowego obiektu przy każdym wywołaniu - w razie potrzeby obiekty mogą być buforowane i ponownie użyte
- może zwrócić podtyp swojego typu zwracanego - w szczególności może zwrócić obiekt, którego klasa implementacji jest nieznana dzwoniącemu. Jest to bardzo cenna i szeroko stosowana funkcja w wielu platformach, które wykorzystują interfejsy jako typ zwracany statycznych metod fabrycznych.
Wszystko sprowadza się do łatwości utrzymania. Najlepszym sposobem na umieszczenie tego jest za każdym razem, gdy używasz new
słowa kluczowego do utworzenia obiektu, łączysz kod, który piszesz z implementacją.
Wzorzec fabryczny pozwala oddzielić sposób tworzenia obiektu od tego, co robisz z tym obiektem. Podczas tworzenia wszystkich obiektów za pomocą konstruktorów zasadniczo instalujesz kod, który używa obiektu do tej implementacji. Kod używający twojego obiektu jest „zależny” od tego obiektu. To może nie wydawać się wielkim problemem na powierzchni, ale kiedy obiekt się zmienia (pomyśl o zmianie podpisu konstruktora lub podklasowaniu obiektu), musisz wracać i porządkować wszystko wszędzie.
Dzisiejsze fabryki zostały w dużej mierze odrzucone na korzyść stosowania Dependency Injection, ponieważ wymagają dużej ilości kodu płyty kotłowej, co okazuje się trochę trudne do utrzymania. Wstrzykiwanie zależności jest zasadniczo równoważne z fabrykami, ale umożliwia określenie deklaratywnego połączenia obiektów (poprzez konfigurację lub adnotacje).
Jeśli konstruktor klasy jest prywatny, nie można utworzyć obiektu dla klasy spoza niej.
class Test{
int x, y;
private Test(){
.......
.......
}
}
Nie możemy stworzyć obiektu dla klasy wyższej spoza niego. Więc nie możesz uzyskać dostępu do x, y spoza klasy. Więc jaki jest pożytek z tej klasy?
Oto odpowiedź: metoda FACTORY .
Dodaj poniższą metodę do powyższej klasy
public static Test getObject(){
return new Test();
}
Teraz możesz stworzyć obiekt dla tej klasy spoza niej. Lubię tę drogę...
Test t = Test.getObject();
Stąd metoda statyczna, która zwraca obiekt klasy przez wykonanie prywatnego konstruktora, jest nazywana metodą FACTORY
.
Static Factory Method
nad publicznym konstruktorem?
Myślałem, że dodam trochę światła do tego postu na temat tego, co wiem. Ta technika była szeroko stosowana w naszym recent android project
. Zamiast tego creating objects using new operator
możesz także użyć static method
do utworzenia klasy. Lista kodów:
//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();
}
}
Metody statyczne obsługują warunkowe tworzenie obiektów : Za każdym razem, gdy wywołujesz konstruktor, obiekt zostanie utworzony, ale możesz tego nie chcieć. załóżmy, że chcesz sprawdzić jakiś warunek tylko wtedy, gdy chcesz utworzyć nowy obiekt. Nie tworzysz za każdym razem nowej instancji Vinotha, chyba że twój warunek jest spełniony.
Kolejny przykład zaczerpnięty z Effective Java .
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
Ta metoda tłumaczy pierwotną wartość logiczną na odwołanie do obiektu boolowskiego. Boolean.valueOf(boolean)
Sposób obrazuje nam, że nigdy nie tworzy obiekt. Zdolność static factory methods
do zwrócenia tego samego obiektu z powtórzeń invocations
pozwala klasom zachować ścisłą kontrolę nad tym, jakie instancje istnieją w dowolnym momencie.
Static factory methods
polega na tym, że w przeciwieństwie do tego constructors
, mogą zwrócić object
dowolny subtype
typ zwrotu. Jednym z zastosowań tej elastyczności jest to, że API może zwracać obiekty bez upubliczniania swoich klas. Ukrywanie klas implementacji w ten sposób prowadzi do bardzo zwartego API.
Calendar.getInstance () jest doskonałym przykładem na powyższe, tworzy go w zależności od ustawień regionalnych BuddhistCalendar
, JapaneseImperialCalendar
lub przez domyślny Georgian
.
Innym przykładem, który mógłbym pomyśleć, jest Singleton pattern
uczynienie konstruktorów prywatnymi, stworzenie własnej getInstance
metody, w której upewnisz się, że zawsze dostępna jest tylko jedna instancja.
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;
}
}
Metoda fabryczna metoda, która wyodrębnia tworzenie instancji obiektu. Generalnie fabryki są przydatne, gdy wiesz, że potrzebujesz nowej instancji klasy, która implementuje jakiś interfejs, ale nie znasz klasy implementującej.
Jest to przydatne podczas pracy z hierarchiami pokrewnych klas, dobrym przykładem może być zestaw narzędzi GUI. Możesz po prostu zakodować na stałe wywołania do konstruktorów w celu konkretnych implementacji każdego widżetu, ale jeśli kiedykolwiek chciałbyś zamienić jeden zestaw narzędzi na inny, miałbyś wiele miejsc do zmiany. Korzystając z fabryki, zmniejszasz ilość kodu, którą musisz zmienić.
Jedną z zalet wynikających z fabryki statycznej jest to, że API może zwracać obiekty bez upubliczniania swoich klas. To prowadzi do bardzo kompaktowego API. W java jest to osiągane przez klasę Collections, która ukrywa około 32 klas, co czyni API kolekcji bardzo kompaktowym.
Statyczna metoda fabryczna jest dobra, gdy chcesz mieć pewność, że tylko jedna instancja zwróci konkretną klasę do użycia.
Na przykład w klasie połączeń z bazą danych możesz chcieć, aby tylko jedna klasa utworzyła połączenie z bazą danych, więc jeśli zdecydujesz się przejść z MySQL na Oracle, możesz po prostu zmienić logikę w jednej klasie, a reszta aplikacji będzie użyj nowego połączenia.
Jeśli chcesz zaimplementować pule bazy danych, byłoby to również możliwe bez wpływu na resztę aplikacji.
Chroni resztę aplikacji przed zmianami, które możesz wprowadzić w fabryce, co jest celem.
Powodem tego, że jest statyczny, jeśli chcesz śledzić pewne ograniczone zasoby (liczbę połączeń gniazdowych lub uchwytów plików), ta klasa może śledzić, ile z nich zostało przekazanych i zwróconych, więc nie wyczerpuj ograniczone zasoby.
Jedną z zalet statycznych metod fabrycznych z prywatnym konstruktorem (tworzenie obiektów musi być ograniczone dla klas zewnętrznych, aby upewnić się, że instancje nie są tworzone zewnętrznie) jest to, że można tworzyć klasy kontrolowane przez instancję . A klasy kontrolowane przez instancję gwarantują, że nie istnieją dwie równe odrębne instancje ( a.equals (b) wtedy i tylko wtedy, gdy a == b ) podczas działania programu oznacza, że możesz sprawdzić równość obiektów za pomocą operatora == zamiast metody równości , zgodnie z Effective java.
Zdolność statycznych metod fabrycznych do zwracania tego samego obiektu z powtarzających się wywołań pozwala klasom zachować ścisłą kontrolę nad tym, jakie instancje istnieją w dowolnym momencie. Klasy, które to robią, są kontrolowane przez instancje. Istnieje kilka powodów, dla których warto pisać klasy kontrolowane przez instancję. Kontrola instancji pozwala klasie zagwarantować, że jest to singleton (pozycja 3) lub nie można go zainstalować (pozycja 4). Pozwala także klasie niezmiennej (pozycja 15) na zagwarantowanie, że nie istnieją dwa równe przypadki: a. Równe (b) wtedy i tylko wtedy, gdy a == b. Jeśli klasa zapewni tę gwarancję, wówczas jej klienci mogą użyć operatora == zamiast metody equals (Object), co może poprawić wydajność. Rodzaje wyliczeń (pozycja 30) zapewniają tę gwarancję.
From Effective Java, Joshua Bloch (pozycja 1, strona 6)
statyczny
Członek zadeklarowany ze słowem kluczowym „static”.
metody fabryczne
Metody, które tworzą i zwracają nowe obiekty.
w Javie
Język programowania odnosi się do znaczenia „statyczny”, ale nie do definicji „fabryki”.
Implementacja Java zawiera klasy narzędzi java.util.Arrays i java.util.Collections oba zawierają statyczne metody fabryczne , ich przykłady i sposób użycia:
Arrays.asList("1","2","3")
Collections.synchronizedList(..), Collections.emptyList(), Collections.unmodifiableList(...)
(Tylko niektóre przykłady mogą sprawdzić javadocs pod kątem przykładów metod moralnych https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html )
Również klasa java.lang.String ma takie statyczne metody fabryczne :
String.format(...), String.valueOf(..), String.copyValueOf(...)