sobota, 1 marca 2014

Metoda wytwórcza (klasowy)

Metoda wytwórcza (Factory method)

Umożliwia klasom przekazanie tworzenia egzemplarzy podklasom. Jak sama nazwa wskazuje wzorzec ten sluży do tworzenia obiektów. Jest podobny do wzorca budowniczy oraz fabryki abstrakcyjnej. Poniżej opisze różnice co wyróżnia metode wytwórczą od powyższych wzorców. Zanim jednak to zrobie wydaje mi się, że najłatwiej będzie zacząć od przykładu.
Podobnie jak dla budowniczego przykład będzie związany z pizza.


1. Na początek tworzymy klase abstrakcyjną Pizza wraz z metoda getPrice() zracającą cenę danej pizzy. Narazie jednak nie znamy ceny więc metoda pozostaje abstrakcyjna.
abstract class Pizza {
    public abstract double getPrice();
}
2. Konkretny rodzaj pizzy ze zdefiniowaną ceną.
class HamAndMushroomPizza extends Pizza {
    private double price = 8.5;
 
    public double getPrice() {
        return price;
    }
}
3. Analogicznie jak powyżej inny rodzaj pizzy z inna ceną.
class DeluxePizza extends Pizza {
    private double price = 10.5;
 
    public double getPrice() {
        return price;
    }
}
4. Nie wymaga komentarza.
class HawaiianPizza extends Pizza {
    private double price = 11.5;
 
    public double getPrice() {
        return price;
    }
}
5. Teraz natomiast tworzymy Fabryke pizzy, w której umieszczony został typ enum z konkretnymi rodzajami pizzy, takimi jak zdefiniowaliśmy powyżej, inaczej nie miałoby to sensu. W klasie tej jak widać poniżej mamy metode createPizza(). Jest to metoda statyczna, która jako argument przyjmuje konkretny rodzaj pizzy. Prosze zwrócić uwagę, iż rodzaj ten jest enumem zdefiniowanym właśnie w tej klasie. Na podstawie typu jaki metoda otrzymała zwraca konkretny rodzaj pizzy. Jeżeli argument będzie niepoprawny rzuci wyjątkiem. Można to zmienić. Każdy może na własny sposób zaimplementować taki przypadek zdarzenia:-). Ta klasa to "engine" całego wzorca. Tutaj widać różnice jaką wyróżnia się ten wzorzec.
class PizzaFactory {
    public enum PizzaType {
        HamMushroom,
        Deluxe,
        Hawaiian
    }

    public static Pizza createPizza(PizzaType pizzaType) {
        switch (pizzaType) {
            case HamMushroom:
                return new HamAndMushroomPizza();
            case Deluxe:
                return new DeluxePizza();
            case Hawaiian:
                return new HawaiianPizza();
        }
        throw new IllegalArgumentException("The pizza type " + pizzaType + " is not recognized.");
    }
}
6. Ostatni fragment kodu to testowanie/main programu. Tutaj można sprawdzić czy wszystko działa według naszych oczekiwań. Jest to jakaś możliwość przetestowania programu. Każdy może zrobić to na własny sposób. Nasz for, który jest de-facto foreach-em jako typ iterowany wybiera enuma z klasy PizzaFactory. Możemy o to poprosić, ponieważ jest to enum. Będziemy iterowali po całym zbiorze enuma, czyli stworzymy każdy rodzaj pizzy i podamy jego cene. Następnie korzystamy z metody statycznej z klasy PizzaFactory przekazując jej typ pizzy jaki chcemy stworzyć i od razu w jednej linijce prosimy o podanie ceny za dany rodzaj pizzy.
class PizzaLover {
    /**
     * Create all available pizzas and print their prices
     */
    public static void main (String args[]) {
        for (PizzaFactory.PizzaType pizzaType : PizzaFactory.PizzaType.values()) {
            System.out.println("Price of " + pizzaType + " is " + PizzaFactory.createPizza(pizzaType).getPrice());
        }
    }
}
Jak już wcześniej wspominałem wzorzec metoda wytwórcza jest podobny do przedwszystkim wzorca fabryka abstrakcyjna oraz budowniczego. Różnice, co do fabryki abstrakcyjnej są przedstawione powyżej w punkcie 5. W metodzie wytwórczej metoda createPizza jest metoda statyczna. Podobnie jak metoda GUIFactory z rozdziału o fabryce abstrakcyjnej. Jednak różnica polega na tym, iż teraz metoda createPizza() przyjmuje rodzaj konkretnej pizzy. Meoda GUIFactory sama na podstawie tego, co ustaliła wewnatrz samej siebie określała jakiego rodzaju przycisk ma stworzyć. Tak więc gdyby przełożyć przykład z fabryki abstrakcyjnej do metody wytwórczej musielibyśmy najpierw stworzyć odpowiedniego enuma z każdym rodzajem przycisku. Następnie przerobić metodę, tak by przyjmowała jako argument naszego enuma i na podstawie tego enuma zwracała odpowiedni typ przycisku. Podsumowywując zachęcam do przeczytania rodziału o fabryce abstrakcyjnej oraz budowniczym dla lepszego zrozumienia powyższych jak że podobnych do siebie wzorców. Różnice pomiędzy fabryką, a budowniczym opisałem w rozdziale o fabryce, dlatego warto choć raz przeczytać.

Na zakończenie rozważań o metodzie fabrykującej przedstawiam diagram klas:


Brak komentarzy:

Prześlij komentarz