JavaRush /Blog Java /Random-PL /Fabryczny wzór projektowy

Fabryczny wzór projektowy

Opublikowano w grupie Random-PL
Cześć przyjacielu! Dzisiaj będziemy kontynuować z Wami naukę wzorców projektowych. W tym wykładzie będziemy rozmawiać o Fabryce. Omówimy z Tobą, jaki problem można rozwiązać za pomocą tego szablonu i przyjrzymy się przykładowi, jak fabryka pomaga otworzyć kawiarnię. Podam ci także 5 prostych kroków, jak stworzyć fabrykę. Fabryczny wzór projektowy - 1Aby być na bieżąco ze wszystkimi i łatwo zrozumieć istotę, powinieneś znać następujące tematy:
  • Dziedziczenie w Javie
  • Zawężanie i rozwijanie typów referencyjnych w Javie
  • Interakcja pomiędzy różnymi klasami i obiektami

Co to jest fabryka?

Wzorzec projektowy Fabryka pozwala kontrolować tworzenie obiektów. Proces tworzenia nowego obiektu nie jest aż tak prosty, ale też nie jest zbyt skomplikowany. Wszyscy wiemy, że aby utworzyć nowy obiekt, musimy użyć rozszerzenia new. I może się wydawać, że nie ma tu nic do załatwienia, ale tak nie jest. Trudności mogą się pojawić, gdy nasza aplikacja posiada pewną klasę, która ma wielu potomków i konieczne jest utworzenie instancji określonej klasy w zależności od pewnych warunków. Fabryka to wzorzec projektowy, który pomaga rozwiązać problem tworzenia różnych obiektów w zależności od pewnych warunków. Streszczenie, prawda? Większa szczegółowość i przejrzystość pojawi się, gdy spojrzymy na poniższy przykład.

Tworzymy różne rodzaje kaw

Załóżmy, że chcemy zautomatyzować kawiarnię. Musimy nauczyć się przygotowywać różne rodzaje kawy. W tym celu w naszej aplikacji utworzymy klasę kawy i jej pochodne: Americano, cappuccino, espresso, latte – czyli rodzaje kaw, które będziemy przygotowywać. Zacznijmy od ogólnej klasy kawy:
public class Coffee {
    public void grindCoffee(){
        // перемалываем кофе
    }
    public void makeCoffee(){
        // делаем кофе
    }
    public void pourIntoCup(){
        // наливаем в чашку
    }
}
Następnie utwórzmy jego spadkobierców:
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Nasi klienci będą zamawiać jakiś rodzaj kawy i ta informacja musi zostać przekazana do programu. Można to zrobić na różne sposoby, na przykład za pomocą String. Ale najlepiej nadaje się do tych celów enum. Stwórzmy enumi zdefiniujmy w nim rodzaje kaw, na które przyjmujemy zamówienia:
public enum CoffeeType {
    ESPRESSO,
    AMERICANO,
    CAFFE_LATTE,
    CAPPUCCINO
}
Świetnie, teraz napiszmy kod dla naszej kawiarni:
public class CoffeeShop {

    public Coffee orderCoffee(CoffeeType type) {
        Coffee coffee = null;

        switch (type) {
            case AMERICANO:
                coffee = new Americano();
                break;
            case ESPRESSO:
                coffee = new Espresso();
                break;
            case CAPPUCCINO:
                coffee = new Cappucсino();
                break;
            case CAFFE_LATTE:
                coffee = new CaffeLatte();
                break;
        }

        coffee.grindCoffee();
        coffee.makeCoffee();
        coffee.pourIntoCup();

        System.out.println("Вот ваш кофе! Спасибо, приходите еще!");
        return coffee;
    }
}
Metodę orderCoffeemożna podzielić na dwa elementy:
  1. Tworzenie konkretnej instancji kawy w bloku switch-case. W tym miejscu Fabryka tworzy określony typ w zależności od warunków.
  2. Sam preparat polega na rozdrobnieniu, ugotowaniu i przelaniu do kubka.
Co warto wiedzieć, jeśli w przyszłości konieczne będzie wprowadzenie zmian w metodzie:
  1. Sam algorytm przygotowania (mielenie, gotowanie i nalewanie do kubka) pozostanie niezmieniony (przynajmniej mamy taką nadzieję).
  2. Ale asortyment kaw może się zmienić. Może zaczniemy robić mokkę.. Mokkę.. Mokkachi... Niech go Bóg błogosławi, nowy rodzaj kawy.
Można już założyć, że w przyszłości z pewnym prawdopodobieństwem będziemy musieli dokonać zmian w metodzie, w bloku switch-case. Możliwe też, że w naszej kawiarni metoda orderCoffeenie będzie jedynym miejscem, w którym tworzymy różne rodzaje kaw. Dlatego zmian trzeba będzie dokonać w kilku miejscach. Prawdopodobnie już rozumiesz, o co mi chodzi. Musimy dokonać refaktoryzacji. Przenieś blok odpowiedzialny za tworzenie kawy do osobnej klasy z dwóch powodów:
  1. Logikę tworzenia kawy będziemy mogli ponownie wykorzystać w innych miejscach.
  2. Jeśli zakres się zmieni, nie będziemy musieli edytować kodu wszędzie tam, gdzie będzie używana kreacja kawy. Wystarczy zmienić kod tylko w jednym miejscu.
Innymi słowy, czas zamknąć fabrykę.

Piłujemy naszą pierwszą fabrykę

W tym celu utwórzmy nową klasę, która będzie odpowiedzialna jedynie za utworzenie niezbędnych instancji klas kawowych:
public class SimpleCoffeeFactory {
    public Coffee createCoffee (CoffeeType type) {
        Coffee coffee = null;

        switch (type) {
            case AMERICANO:
                coffee = new Americano();
                break;
            case ESPRESSO:
                coffee = new Espresso();
                break;
            case CAPPUCCINO:
                coffee = new Cappucino();
                break;
            case CAFFE_LATTE:
                coffee = new CaffeLatte();
                break;
        }

        return coffee;
    }
}
Gratulacje! Właśnie zaimplementowaliśmy wzorzec projektowy Factory w jego najprostszej formie. Chociaż wszystko mogłoby być jeszcze prostsze, gdyby metoda była createCoffeestatyczna. Ale wtedy stracilibyśmy dwie możliwości:
  1. Dziedzicz SimpleCoffeeFactoryi zastępuj createCoffee.
  2. Zaimplementuj wymaganą implementację fabryczną na naszych zajęciach.
Skoro już mowa o wdrażaniu. Musimy wrócić do kawiarni i wdrożyć naszą fabrykę kawy.

Wprowadzenie fabryki do kawiarni

Przepiszmy naszą klasę kawiarni, korzystając z fabryki:
public class CoffeeShop {

    private final SimpleCoffeeFactory coffeeFactory;

    public CoffeeShop(SimpleCoffeeFactory coffeeFactory) {
        this.coffeeFactory = coffeeFactory;
    }

    public Coffee orderCoffee(CoffeeType type) {
        Coffee coffee = coffeeFactory.createCoffee(type);
        coffee.grindCoffee();
        coffee.makeCoffee();
        coffee.pourIntoCup();

        System.out.println("Вот ваш кофе! Спасибо, приходите еще!");
        return coffee;
    }
}
Świetnie. Spróbujmy teraz schematycznie i zwięźle opisać strukturę wzorca projektowego Factory.

5 kroków do otwarcia własnej fabryki

Krok 1. W swoim programie masz klasę z kilkoma potomkami, jak na obrazku poniżej: Fabryczny wzór projektowy - 2Krok 2. Tworzysz klasę enum, w której definiujesz zmienną wyliczeniową dla każdej klasy potomka:
enum CatType {
    LION,
    TIGER,
    BARSIK
}
Krok 3. Budujesz swoją fabrykę. Nazywasz to MyClassFactory, kod jest poniżej:
class CatFactory {}
Krok 4. Tworzysz w swojej fabryce metodę createMyClass, która przyjmuje zmienną - enum MyClassType. Kod poniżej:
class CatFactory {
    public Cat createCat(CatType type) {

    }
}
Krok 5. W treści metody piszesz blok, switch-casew którym iterujesz po wszystkich wartościach wyliczeniowych i tworzysz instancję klasy odpowiadającą enumwartości:
class CatFactory {
        public Cat createCat(CatType type) {
            Cat cat = null;

            switch (type) {
                case LION:
                    cat =  new Barsik();
                    break;
                case TIGER:
                    cat = new Tiger();
                    break;
                case BARSIK:
                    cat =  new Lion();
                    break;
            }

            return cat;
        }
    }
Jak szef.

Jak trenować

Czytanie jest dobre, pisanie kodu jest jeszcze lepsze. Jeśli Twoje imię i nazwisko składa się z parzystej liczby liter, spróbuj stworzyć własną wirtualną pizzerię. Jeśli Twoje imię i nazwisko ma nieparzystą liczbę liter, spróbuj stworzyć wirtualny bar sushi. Jeśli jesteś anonimowy, masz szczęście. Dziś możesz odpocząć.
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION