2009-05-13 17 views
7

Digamos que tengo una clase abstracta Bebida, y un método de fábrica que elige el tipo de bebida (vino, cerveza, etc.) para crear en tiempo de ejecución.Pasar argumentos a una subclase específica, a través de un método de fábrica

Cada bebida necesita algunos argumentos para inicializarse correctamente. Algunos de estos son comunes a todas las bebidas; por ejemplo, todos pueden requerir un argumento de DrinkConfig.

Pero cada bebida puede tener sus propios requisitos únicos también. Tal vez Wine necesite un objeto auxiliar Sommelier para inicializarse. La cerveza no necesita eso, pero puede necesitar sus propios objetos auxiliares.

Entonces, ¿qué debo pasar al método de fábrica? Cuando lo llamo, tengo todos los objetos auxiliares disponibles, así que podría pasarlos a la fábrica. Pero esto podría terminar siendo una gran cantidad de argumentos. ¿Hay una mejor manera de diseñar esto?

EDIT: Supongamos que no puedo simplemente crear los objetos auxiliares en la fábrica; solo están disponibles para la persona que llama.

Respuesta

4

Crearía diferentes métodos de sobrecarga en su clase de fábrica.

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); 
    } 
} 

Editar:

Si se desea efectuar solamente para tener un único método en la clase de fábrica una implementación alternativa sería:

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

Las firmas están bien. El problema es cómo pasar argumentos a su Factory :: CreateDrink() (o como se llame). – dirkgently

+0

Si quería tener un método CreateDrink en la fábrica, podría usar un parámetro enum para especificar qué tipo de bebida quería. No lo creo o el enfoque anterior cumple con el patrón de fábrica de GoF, donde los objetos se crean en la clase de Bebidas (tengo que revisar mi libro esta noche), pero me parece mucho más pragmático y aún mantiene el beneficio principal de centralización de creación de objetos para jerarquías de subclase. – sipwiz

+0

Después de consultar mi libro GoF Design Patterns, me complace que el ejemplo que proporcioné más arriba se asemeje a la forma en que usa Factory como parte del patrón de diseño de Abstract Factory. Para conformarse por completo, debe haber una clase de fábrica abstracta de la que DrinkFactory hereda, pero en casos simples como este, normalmente lo dejo fuera. Sería bastante fácil refactorizar DrinkFactory si se requiriera otra fábrica de concreto. – sipwiz

0

me siento tentado a dar una solución ingenua donde su los ingredientes se derivan de una clase base 'DrinkIngredients'. Tendrá que coincidir con la subclase que se utilizará para una bebida en particular.

Aparentemente, puede tener la tentación de crear otra fábrica para los ingredientes, pero eso provocaría un problema de huevo y gallina.

0

Generalmente, existe un método de fábrica para ocultar estos detalles. Una pregunta importante es de dónde viene el Sommelier: si todos estos otros ayudantes son únicos o pueden adquirirse de una fuente conocida, entonces instanciar la fábrica la información necesaria para ir y encontrarlos, para que su código de llamada no necesite preocuparse por eso

Además, en muchos casos, un marco como Spring se usará para permitirle describir estas relaciones en un archivo de configuración en lugar de en un código.

Si realmente necesita pasar los ayudantes en tiempo de ejecución desde el código de llamada, sugiero leer el documento 'Argumentos y resultados' (http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.50.7565) que describe un patrón común para ordenar argumentos complejos. Esencialmente, crearía una colección intermedia de los parámetros necesarios y los pasaría a la fábrica.

2

El método de fábrica debe abstraer los detalles de cómo crear valores. Por lo tanto, no debe pasar objetos auxiliares al método de fábrica, el método de fábrica debería crear el objeto auxiliar que necesita y pasarlo al constructor apropiado.

0

En casos como este, suelo mirar hacia otras soluciones en lugar de pasar variables.

Por ejemplo, en su caso - WineFactory necesidad de un sumiller, por lo que se puede construir el vino apropiado -

Este es un gran caso de uso para la inyección de dependencias en tiempo de ejecución. Un marco de inyección de dependencias de alguna forma haría que esto fuera muy simple, comprensible, y solo un tipo de trabajo sin necesidad de tener todas estas propiedades pasadas.

1

A Factory debería estar creando objetos muy similares en primer lugar. Esto significa que, aunque todos estos objetos son bebidas, el método de fábrica puede no ser apropiado porque cada bebida es simplemente muy diferente de otra.

Dicho esto, en su lugar podría pasar una Lista de objetos de tamaño igual al número de propiedades que desea establecer. Cada objeto representaría el valor que desea establecer en el constructor del objeto apropiado, en el orden en el que desea establecer estas variables. La desventaja de esto es que tienes que formatear una lista fuera de la fábrica antes de hacer la llamada, lo cual es algo torpe.

0

Esto parece una caja perfecta para el patrón Builder. Utilice el patrón Factory para crear objetos similares y el patrón Builder para construir objetos complejos y diferentes. Intentar utilizar el patrón Factory para este problema conducirá a muchos constructores de inicialización diferentes (con diferentes números/tipos de parámetros) para los diferentes objetos.

Cuestiones relacionadas