Jakie są statyczne metody fabryczne?

261

Co to jest metoda „fabryki statycznej”?

freddiefujiwara
źródło
Alternatywnymi statycznymi metodami fabrycznymi są wstrzykiwanie zależności.
CMCDragonkai
1
@ThangPham Odpowiedź Jasona Owena jest błędna, ponieważ rzekomo mówi o wzorcu metody fabrycznej, który bardzo różni się od wzorca statycznej metody fabrycznej, o którym faktycznie mówi. Tak więc, chociaż dobrze radzi sobie z udzieleniem odpowiedzi na rzeczywiste pytanie, nie sądzę, aby można je było zaakceptować w obecnym stanie, ponieważ wprowadza niepowiązany wzorzec i zwiększa już i tak niezwykle powszechne zamieszanie na temat różnicy między tymi dwoma wzorami.
Theodore Murdock
@CMCDragonkai Myślę, że wstrzykiwanie zależności i fabryka statyczna są różne. Fabryka statyczna może być wymagana nawet w przypadku wstrzykiwania zależności w celu wystąpienia zależności, które mają zostać wstrzyknięte.
Karan Khanna

Odpowiedzi:

126

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, getDbConnectionktó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);
     //...
   }
}
Matthew Flaschen
źródło
jeśli dobrze rozumiem, czy możesz dodać dostępnyConnections.add (db) do metody returnDbConnection (DbConnection db)?
Haifeng Zhang
@haifzhan, to naprawdę nie jest kompletne, ale w porządku.
Matthew Flaschen
@MatthewFlaschen należy również pomniejszyć wartość totalConnection podczas powrotu połączenia?
toczący się kamień
@Sridhar, nie, to liczba istniejących połączeń (śledzonych w taki sposób, że nie jest tworzone więcej niż MAX_CONNS), a nie liczba, która się kręci.
Matthew Flaschen,
@MatthewFlaschen twoja metoda zostanie złapana przez sonarcube jako błąd blokujący, jeśli DbConnection można zamknąć.
Awan Biru,
477

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 statictak, ż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ć, nulljeś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.

Jason Owen
źródło
32
Należy zauważyć, że statyczna metoda fabryczna nie jest tym samym, co wzorzec metody fabrycznej z wzorców projektowych [Gamma95, s. 1. 107]. Statyczna metoda fabryczna opisana w tym punkcie nie ma bezpośredniego odpowiednika we wzorach projektowych.
Josh Sunshine
Wypłatą dla mnie za tę odpowiedź jest odniesienie do obiektów z puli. Dokładnie tak używam wzorca metody fabrycznej. Udostępniono metody fabryczne, które pomagają kontrolować cykl życia obiektu: „create” albo wyciąga obiekt z puli, albo tworzy nową instancję, jeśli pula jest pusta, „zniszczyć” zwraca ją do puli do ponownego wykorzystania w przyszłości.
MutantXenu
2
Naprawdę powinieneś używać „statycznego wzorca metody fabrycznej” wszędzie tam, gdzie mówisz „wzorzec metody fabrycznej” w tym poście, używasz niewłaściwego terminu. Link do artykułu w Wikipedii dotyczy też innego wzoru niż ten, o którym mówisz. Wzorzec metody fabrycznej powinien być prawdopodobnie nazywany wzorcem „Interfejs fabryczny”, ponieważ wymaga użycia kilku obiektów fabrycznych, które implementują interfejs fabryczny, aby umożliwić tworzenie pojedynczego algorytmu, a także pracę z instancjami interfejsu, poprzez zaakceptowanie obiektu fabrycznego które mogą wytworzyć określoną pożądaną podklasę.
Theodore Murdock
8
Zgadzam się z @TheodoreMurdock. Używasz złego terminu. Mówisz o „statycznej metodzie fabrycznej” Joshua Blocha, ale używasz terminu „fabryczny wzorzec metody” GoF. Edytuj go, aby inni ludzie nie mogli go źle zrozumieć.
emeraldhieu
1
Pamiętaj, że konstruktor nie musi być prywatny. Klasa może zapewniać zarówno publiczne metody statycznej fabryki, jak i konstruktory.
Kevin
171

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:

  • wartość
  • uzyskac instancje
  • newInstance
Grygoriy Gonchar
źródło
Czy możesz mi powiedzieć różnicę między nowymi A () i A.newInstance ()? i wewnątrz A.newInstance co powinniśmy zrobić?
Shen
69

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();
Rasmus Faber
źródło
Próbowałem więc zaimplementować przykład, ale nie jestem pewien, jak to działa. Czy dwie metody createWithBar i createWithoutBar mają wywoływać 2 prywatne konstruktory w klasie Foo?
Essej
@Baxtex: Tak. Każdy wywoła prywatnego konstruktora. Być może tak samo: private Foo(boolean withBar){/*..*/} public static Foo createWithBar(){return new Foo(true);} public static Foo createWithoutBar(){return new Foo(false);}
Rasmus Faber
Myślę, że nie jest to dobrze „skalowane”. Jeśli masz trzy lub więcej parametrów, jak możesz wykorzystać ten pomysł i stworzyć ładną nazwę dla metody?
Dherik
@Dherik: W takim razie prawdopodobnie powinieneś użyć wzorca konstruktora: new FooBuilder (). WithBar (). WithoutFoo (). WithBaz (). Build ();
Rasmus Faber
21
  • 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.

z http://www.javapractices.com/topic/TopicAction.do?Id=21

Soldier.moth
źródło
18

Wszystko sprowadza się do łatwości utrzymania. Najlepszym sposobem na umieszczenie tego jest za każdym razem, gdy używasz newsł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).

cwash
źródło
3
Mówisz, że fabryki potrzebują pomocy? ;)
John Farrell
4
Ha ha! W dzisiejszych czasach myślę, że wszyscy moglibyśmy skorzystać z dofinansowania ... :)
cwash
11

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
.

Santhosh
źródło
1
Dlaczego nazywasz to „rozwiązaniem”? Zadeklarowanie prywatnego konstruktora nie jest „problemem”, jest wzorcem projektowym.
Ojonugwa Jude Ochalifu
1
Zaktualizowano W każdym razie dzięki
Santhosh,
Cześć @Santhosh Mam obawy, dlaczego nie pozwolisz, aby prywatny konstruktor był publiczny? Jeśli nie chcesz tworzyć podklasy, jest dla mnie w porządku, ale jeśli nie zamierzam tworzyć prywatnego konstruktora, czy mamy jakąkolwiek przewagę Static Factory Methodnad publicznym konstruktorem?
Shen
9

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 operatormożesz także użyć static methoddo 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 methodsdo zwrócenia tego samego obiektu z powtórzeń invocationspozwala klasom zachować ścisłą kontrolę nad tym, jakie instancje istnieją w dowolnym momencie.

Static factory methodspolega na tym, że w przeciwieństwie do tego constructors, mogą zwrócić objectdowolny subtypetyp 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, JapaneseImperialCalendarlub przez domyślny Georgian.

Innym przykładem, który mógłbym pomyśleć, jest Singleton patternuczynienie konstruktorów prywatnymi, stworzenie własnej getInstancemetody, 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;
    }
}
Thalaivar
źródło
4

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ć.

Bryan Kyle
źródło
Zakładając, że fabryka zwraca typ interfejsu, a nie konkretną klasę, z którą mamy do czynienia.
Bill Lynch
1
Ta odpowiedź dotyczy wzorca projektowania metody fabrycznej, a nie statycznych metod fabrycznych. Statyczne metody fabryczne to po prostu publiczna metoda statyczna, która zwraca instancję klasy. Więcej informacji na ten temat znajduje się w rozdziale 2 Efektywnej Java.
Josh Sunshine
4

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.

Rakesh Chauhan
źródło
2

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.

James Black
źródło
2

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)

SherlockHomeless
źródło
1

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”.

Markiz Lorne
źródło
Odpowiedzi @Victor nie muszą zawierać argumentów. Fakty powinny wystarczyć: jeśli są kontrowersyjne, można je poprzeć argumentami lub cytowaniem. Nie wiem, czy jest tu coś kontrowersyjnego.
Markiz Lorne
Stwierdziłem, że ponieważ odpowiedź była zbyt krótka i naprawdę nie rozumiała dobrze na pierwszy, drugi i trzeci wygląd, w każdym razie OP musi ponownie zapytać. Nieważne, zmieniłem zdanie i staram się usunąć głos negatywny, ale nie mogę.
Victor
@Victor Zdefiniuj „za krótki”. Czasami prawdziwą odpowiedzią jest po prostu „tak”, „nie”, „ani”, albo „oba”. „Zbyt krótki” jest całkowicie subiektywny. Nadal nie rozumiem twojego oryginalnego komentarza. Nie potrzebujesz argumentów do obsługi definicji. Zgodnie z definicją. Zredagowałem swoją odpowiedź, aby można było teraz usunąć głosowanie negatywne.
Markiz Lorne
Oczywiście jest subiektywny ... wszystkie odpowiedzi na przepełnienie stosu są subiektywne, w rzeczywistości są powiązane z poziomem wiedzy autora i chęcią odpowiedzi. Naprawdę nie rozumiem twojej odpowiedzi, być może było za krótkie.
Victor
@Victor Rubbish. Sprawy nie są subiektywne, podobnie jak sprawy, które można wywnioskować na podstawie faktów lub aksjomatów. Z drugiej strony „zbyt krótki” jest subiektywny i już się nim zająłem. Ta odpowiedź jest zasadniczo taka sama jak ta , o której nie skomentowałeś. Twoje komentarze pozostają niejasne.
Markiz Lorne
1

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:

Również klasa java.lang.String ma takie statyczne metody fabryczne :

  • String.format(...), String.valueOf(..), String.copyValueOf(...)
Владимир Дворник
źródło