¿Las clases base como fábricas?

14

Estaba escribiendo algún código durante el fin de semana y me encontré con ganas de escribir una fábrica como un método estático en una clase base.

Mi pregunta es simplemente para saber si se trata de un enfoque idomático de c #.

Mi percepción de que podría no ser así proviene del hecho de que la clase base tiene conocimiento de la clase derivada.

Dicho esto, no estoy seguro de una forma más sencilla de obtener el mismo resultado. Toda otra clase de fábrica parece (al menos para mí) una complejidad innecesaria (?)

Algo como:

class Animal
{
  public static Animal CreateAnimal(string name)
  {
     switch(name)
     {
        case "Shark":
          return new SeaAnimal();
          break;
        case "Dog":
          return new LandAnimal();
          break;
        default:
          throw new Exception("unknown animal");
     }
  }
}
class LandAnimal : Animal
{
}

class SeaAnimal : Animal
{
}
    
pregunta Aaron Anodide 05.03.2012 - 17:12
fuente

5 respuestas

13

Bueno, la ventaja de una clase de fábrica separada es que se puede simular en pruebas unitarias.

Pero si no va a hacer eso, o lo hace polimórfico de otra manera, entonces un método de Fábrica estático en la clase en sí está bien.

    
respondido por el pdr 05.03.2012 - 17:20
fuente
18

Podrías usar Generics para evitar la instrucción de cambio y desacoplar las implementaciones posteriores de la clase base también:

 public static T CreateAnimal<T>() where T: new, Animal
 {
    return new T();
 }

Uso:

LandAnimal rabbit = Animal.CreateAnimal();  //Type inference should should just figure out the T by the return indicated.

o

 var rabbit = Animal.CreateAnimal<LandAnimal>(); 
    
respondido por el Nick Nieslanik 05.03.2012 - 17:36
fuente
5

Llevado al extremo, la fábrica también podría ser genérica.

interface IFactory<K, T> where K : IComparable
{
    T Create(K key);
}

Entonces, uno puede crear cualquier tipo de fábrica de objetos, lo que a su vez podría crear cualquier tipo de objeto. No estoy seguro de si eso es más simple, ciertamente es más genérico.

No veo nada malo con una instrucción de cambio para una implementación de fábrica pequeña. Una vez que esté en un gran número de objetos o posibles jerarquías de clases diferentes de objetos, creo que un enfoque más genérico es el más adecuado.

    
respondido por el Jon Raynor 05.03.2012 - 19:05
fuente
1

Mala idea. En primer lugar, viola el principio abierto-cerrado. Para cualquier animal nuevo, tendría que meterse con su clase base otra vez y potencialmente lo rompería. Las dependencias irían por el camino equivocado.

Si necesita crear animales a partir de una configuración, una construcción como esta estaría bien, aunque usar la reflexión para obtener el tipo que coincida con el nombre y crear una instancia utilizando la información de tipo obtenida sería una mejor opción.

Pero de todos modos, debe crear una clase de fábrica dedicada, desvinculada de la jerarquía de clases de animales y devolver una interfaz IAnimal en lugar de un tipo base. Entonces se volvería útil, habrías logrado un poco de desacoplamiento.

    
respondido por el Martin Maat 13.10.2018 - 08:10
fuente
0

Esta pregunta es oportuna para mí: ayer escribí casi exactamente ese código. Simplemente reemplace "Animal" con lo que sea relevante en mi proyecto, aunque me quedo con "Animal" por el bien de la discusión aquí. En lugar de una declaración de 'cambio', tuve una serie algo más compleja de declaraciones 'if', que involucran más que solo comparar una variable con ciertos valores fijos. Pero eso es un detalle. Un método estático de fábrica parecía una forma ingeniosa de diseñar cosas, ya que el diseño surgió de la refactorización de desorden de código rápido y sucio.

Rechacé este diseño debido a que la clase base tenía conocimiento de la clase derivada. Si las clases LandAnimal y SeaAnimal son pequeñas, ordenadas y fáciles, pueden estar en el mismo archivo fuente. Pero tengo grandes métodos complejos para leer archivos de texto que no cumplen con los estándares definidos oficialmente. Quiero que mi clase LandAnimal esté en su propio archivo fuente.

Eso conduce a la dependencia de archivos circulares: LandAnimal se deriva de Animal, pero Animal necesita saber que LandAnimal, SeaAnimal y otras quince clases existen. Saqué el método de fábrica, lo puse en su propio archivo (en mi aplicación principal, no en mi biblioteca de Animales). Tener un método de fábrica estático parecía lindo e inteligente, pero me di cuenta de que en realidad no resolvía ningún problema de diseño.

No tengo idea de cómo se relaciona esto con C # idiomático, ya que cambio mucho los idiomas, generalmente ignoro los modismos y las convenciones propias de los idiomas y las pilas de desarrolladores fuera de mi trabajo habitual. Si algo mi C # puede parecer "pythonic" si eso es significativo. Mi objetivo es la claridad general.

Además, no sé si habría alguna ventaja en el uso del método de fábrica estática en el caso de clases pequeñas y simples que probablemente no se extenderán en el trabajo futuro: tenerlo todo en un archivo de origen podría ser bueno en algunos casos.

    
respondido por el DarenW 12.10.2018 - 22:43
fuente

Lea otras preguntas en las etiquetas