2009-05-13 11 views
7

Załóżmy, że mam napój klasy abstrakcyjnej i metodę fabryczną, która wybiera rodzaj napoju (wino, piwo itp.) Do utworzenia w czasie wykonywania.Przekazywanie argumentów do konkretnej podklasy za pomocą metody fabrycznej

Każdy drink potrzebuje kilku argumentów, aby poprawnie się zainicjować. Niektóre z nich są wspólne dla wszystkich napojów; na przykład wszystkie mogą wymagać argumentu DrinkConfig.

Ale każdy napój może mieć swoje własne unikalne wymagania. Może Wine potrzebuje obiektu pomocnika Sommeliera, aby się zainicjować. Piwo nie potrzebuje tego, ale może potrzebować własnych obiektów pomocniczych.

Co powinienem przejść do metody fabrycznej? Kiedy to nazywam, mam dostępne wszystkie obiekty pomocnicze, więc mogłem po prostu przekazać je wszystkie do fabryki. Ale może to oznaczać wiele kłótni. Czy istnieje lepszy sposób na zaprojektowanie tego?

EDYCJA: Załóżmy, że nie mogę po prostu tworzyć obiektów pomocniczych w fabryce; są dostępne tylko od dzwoniącego.

Odpowiedz

4

Tworzyłbym różne metody przeciążania w twojej klasie fabrycznej.

public class DrinkFactory { 

    public static Drink CreateBeer(DrinkConfig config, string hops) { 
     return new Beer(config, hops); 
    } 

    public static Drink CreateWine(DrinkConfig config, string grapes, int temperature) { 
     return new Wine(config, grapes, temperature); 
    } 
} 

Edit:

Jeśli jest to pożądane, aby mieć tylko jedną metodę w klasie produkcyjnej alternatywą wdrożenie byłoby:

public enum DrinksEnum { 
    Beer, 
    Wine 
} 

public class DrinkFactory { 

    public static Drink CreateDrink(DrinksEnum drinkType, DrinkConfig config) { 
     switch(drinkType) { 
      case DrinksEnum.Beer: 
       return new Beer(config); 
      case DrinksEnum.Wine: 
       return new Wine(config); 
      default: 
       throw new ApplicationException("Drink type not recognised."); 
     } 
    } 
} 
+0

Podpisy są w porządku. Problem polega na tym, w jaki sposób przekazujesz argumenty do swojego Factory :: CreateDrink() (lub jakkolwiek to się nazywa). – dirkgently

+0

Jeśli chcesz mieć metodę CreateDrink w fabryce, możesz użyć parametru wyliczeniowego, aby określić, jaki rodzaj napoju chciałeś. Nie wierzę w to, czy powyższe podejście jest zgodne z wzorcem fabryk GoF, w którym przedmioty powstają w klasie Drink (muszę dziś sprawdzić moją książkę), ale uważam, że jest to o wiele bardziej pragmatyczne i nadal utrzymuje główną korzyść centralizacji tworzenia obiektów dla hierarchii podklasowych. – sipwiz

+0

Po sprawdzeniu mojej książki GoF Design Patterns cieszę się, że powyższy przykład podałem w przybliżeniu, w jaki sposób używasz Fabryki jako części wzorca projektu Abstrakt Factory. Aby całkowicie się zgadzać, powinna istnieć abstrakcyjna klasa fabryczna, z której dziedziczy DrinkFactory, ale w prostych przypadkach, takich jak ten, zwykle go pomijam. Łatwo byłoby refakturować DrinkFactory, gdyby potrzebna była inna fabryka betonu. – sipwiz

0

Kusi mnie, aby zapewnić naiwne rozwiązanie, gdzie składniki pochodzą z klasy bazowej "DrinkIngredients". Będziesz musiał dopasować podklasę do konkretnego napoju.

Wygląda na to, że możesz pokusić się o stworzenie kolejnej fabryki składników - ale to mogłoby doprowadzić do problemu kurczaków i jaj.

0

Ogólnie rzecz biorąc istnieje metoda fabryczna do ukrycia tych szczegółów. Jednym z ważnych pytań jest to, skąd pochodzi Sommelier - jeśli wszyscy z tych innych pomocników są singletonami lub mogą zostać pozyskani ze znanego źródła, to zainicjuj fabrykę niezbędne informacje, aby je znaleźć i znaleźć, aby Twój kod wywoławczy nie potrzebował martwić się o to.

Ponadto, w wielu przypadkach, struktura taka jak Spring byłaby używana, aby umożliwić opisanie tych relacji w pliku konfiguracyjnym, a nie w kodzie.

Jeśli naprawdę potrzebujesz przekazać pomocników w czasie wykonywania z kodu wywołującego, proponuję przeczytać artykuł "Argumenty i wyniki" (http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.50.7565), który opisuje wspólny wzorzec do zestawiania skomplikowanych argumentów. Zasadniczo stworzysz pośredni zbiór niezbędnych parametrów i przekażesz go do fabryki.

2

Metoda fabryk powinna zawierać szczegóły dotyczące tworzenia wartości. Dlatego nie powinno się przekazywać obiektów pomocniczych do metody fabryki, metoda fabryki powinna tworzyć obiekt pomocniczy, który potrzebuje i przekazywać go do odpowiedniego konstruktora.

0

W takich przypadkach zazwyczaj szukam innych rozwiązań zamiast przekazywania zmiennych.

Na przykład, w przypadku - WineFactory konieczności sommelier, więc można go skonstruować odpowiedni Wine -

To jest wielki przypadek użycia do iniekcji zależnościach środowiska wykonawczego. Ramy wtrysku zależności w jakiejś formie sprawiają, że jest to bardzo proste, zrozumiałe i po prostu rodzaj pracy, bez konieczności przenoszenia wszystkich tych właściwości.

1

Fabryka powinna przede wszystkim tworzyć bardzo podobne obiekty. Oznacza to, że chociaż wszystkie te przedmioty są napojami, metoda fabryczna może nie być odpowiednia, ponieważ każdy napój jest po prostu bardzo różny od innego.

W tym przypadku można zamiast tego przekazać Listę obiektów o wielkości równej liczbie właściwości, które chcesz ustawić. Każdy obiekt będzie wówczas reprezentował wartość, którą chcesz ustawić w konstruktorze odpowiedniego obiektu, w kolejności, w której chcesz ustawić te zmienne. Wadą tego jest to, że przed wywołaniem trzeba sformatować listę poza fabryką, co jest nieco niezgrabne.

0

To wygląda jak idealne etui na wzór Builder. Użyj wzoru Factory do tworzenia podobnych obiektów oraz wzoru Builder do konstruowania złożonych, niepodobnych obiektów. Próba użycia wzorca Factory dla tego problemu doprowadzi do wielu, różnych konstruktorów inicjalizacji (z różnymi numerami/typami parametrów) dla różnych obiektów.

Powiązane problemy