Press "Enter" to skip to content

Wzorce projektowe – Metoda fabrykująca

Po jednorazowym opuszczeniu serii z wzorcami (brak czasu na napisanie czegoś sensownego), dzisiaj wracamy z metodą fabrykującą.

Metoda fabrykująca definiuje interfejs pozwalający na tworzenie obiektów, ale pozwala klasom podrzędnym decydować, jakiej klasy obiekt zostanie utworzony.Wzorzec Metoda Fabrykująca przekazuje odpowiedzialność za tworzenie obiektów do klas podrzędnych.

Definicja zaczerpnięta z książki Rusz głową! Wzorce projektowe

Fabryka samochodowa

Dzisiaj wcielimy się w rolę producenta samochodowego (ostatnio prowadziliśmy salon samochodowy 😉 ). Obecnie produkujemy tylko jedną markę, ale w przyszłości chcielibyśmy rozszerzyć działalność o produkcję różnych marek samochodowych, w zależności od lokalizacji.

Schemat produkcji audi

W chwili obecnej dajemy sobie radę z prowadzeniem produkcji jednej marki, jednak gdybyśmy chcieli teraz rozszerzyć naszą działalność i zacząć produkować pojazdy marki Honda, sprawa zaczyna nam się nieco komplikować, co pokazuje poniższy diagram:

Dwie marki samochodów

Dla pokazania problemu zmieniłem klasę Audi na klasę opisującą naszą firmę. Patrząc na diagram, widzimy, że mamy bardzo dużo powiązań z konkretnymi typami samochodów w naszej firmie. Chcielibyśmy jednak, aby nasza firma nie musiała się przejmować tym, jaki samochód dokładnie produkuje i oddaje do klienta, tylko chcielibyśmy skupić się na ważniejszych rzeczach, jak zarabianie miliardów na produkcji, a sprzedawać po prostu samochody.

Metoda fabrykująca

Z pomocą do rozwiązania takiego problemu przychodzi nam właśnie metoda fabrykująca:

Schemat metody fabrykującej

Metoda fabrykująca jest ściśle powiązana z konkretnym typem (rodziną) produktów (pokazane dalej). Każda fabryka rzeczywista implementuje abstrakcyjną metodę factoryMethod(), w której określa szczegółowe informacje dotyczące tworzonego obiektu. Naszym produktem są samochody, natomiast rzeczywistym samochodem jest każdy konkretny model. Fabryką natomiast jest nasza firma, a fabryką rzeczywistą są fabryki marki samochodów. Dzięki takiemu rozwiązaniu możemy otworzyć fabrykę, która będzie produkowała dla nas samochody marki audi, inna będzie produkowała nam samochody marki Honda, a w przyszłości (jeśli zechcemy) będziemy mogli otworzyć dodatkowe fabryki konkretnych marek.

Powiązanie fabryk z modelami samochodów

Nowa implementacja fabryk samochodowych

Po zestawieniu obok siebie schematu struktury samochodów oraz struktury firmy, da się zauważyć, że posiadamy osobną fabrykę do produkowania samochodów Audi oraz osobną do produkowania samochodów Honda. Dzięki takiemu rozwiązaniu, po przyjściu klienta do naszej firmy, możemy zlecić produkcję odpowiedniej fabryce i zwrócić samochód do klienta na podstawie wymagań, jakie przekazał nam podczas rozmowy ze sprzedawcą.

Podsumowanie

Wzorzec metoda fabrykująca pozwala nam ukryć (przenieść do fabryki rzeczywistej) informacje na temat tworzonego produktu. Jesteśmy pewni, że zawsze stworzymy konkretny produkt (w naszym przypadku samochód), jednocześnie nie przejmując się w jaki sposób zostało to wykonane. Każda rzeczywista fabryka produkuje rzeczywiste produkty powiązane ze swoim typem (Audi produkuje samochody typu A4, A6 itd, ale nie produkuje samochodów marki Hondy, np. Civic). Dzięki temu mamy prostszą rozbudowę naszego systemu oraz mamy pewność, że modyfikacja tworzenia konkretnych modeli nie będzie miała wpływu na klasę naszej firmy.

github

Przykład uruchomienia aplikacji:

public class Startup {
    public static void main(String[] args) {
        OurCompany company = new AudiFactory("Poland", "Audi factory");
        System.out.println(company);
        Car car = company.orderCar("A8");
        System.out.println(car);
        car = company.orderCar("A4");
        System.out.println(car);

        company = new HondaFactory("Japan", "Honda factory");
        System.out.println(company);
        car = company.orderCar("ACCORD");
        System.out.println(car);
    }
}

Wyjście:

OurCompany{place='Poland', name='Audi factory'}
Car{vin='AUDI', make='Audi', model='A8', year='2016'}
Car{vin='AUDI', make='Audi', model='A4', year='2016'}
OurCompany{place='Japan', name='Honda factory'}
Car{vin='HONDA', make='Honda', model='Accord', year='2016'}