Classes base como fábricas?

14

Eu estava escrevendo algum código no fim de semana e me vi querendo escrever uma fábrica como um método estático em uma classe base.

A minha pergunta é simplesmente saber se esta é uma abordagem c idomática?

Meu sentimento de que isso pode não ser vem do fato de que a classe base tem conhecimento da classe derivada.

Dito isso, não tenho certeza de uma maneira mais simples de obter o mesmo resultado. Uma outra classe de fábrica parece (pelo menos para mim) como uma complexidade desnecessária (?)

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
{
}
    
por Aaron Anodide 05.03.2012 / 17:12
fonte

5 respostas

13

Bem, a vantagem de uma classe de fábrica separada é que ela pode ser ridicularizada em testes unitários.

Mas se você não for fazer isso, ou torná-lo polimórfico de qualquer outra forma, então um método Factory estático na própria classe é OK.

    
por 05.03.2012 / 17:20
fonte
18

Você pode usar o Generics para evitar a instrução switch e desacoplar as implementações downstream da classe base também.:

 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.

ou

 var rabbit = Animal.CreateAnimal<LandAnimal>(); 
    
por 05.03.2012 / 17:36
fonte
5

Levada ao extremo, a fábrica também pode ser genérica.

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

Em seguida, pode-se criar qualquer tipo de fábrica de objetos, que por sua vez poderia criar qualquer tipo de objeto. Não tenho certeza se isso é mais simples, certamente é mais genérico.

Não vejo nada de errado com uma instrução switch para uma pequena implementação de fábrica. Uma vez que você está em um grande número de objetos ou possíveis hierarquias de classes diferentes de objetos, acho que uma abordagem mais genérica é mais adequada.

    
por 05.03.2012 / 19:05
fonte
1

Má ideia. Primeiro, viola o princípio aberto-fechado. Para qualquer novo animal você teria que mexer com sua classe base novamente e você potencialmente iria quebrá-lo. As dependências seguiriam o caminho errado.

Se você precisa criar animais a partir de uma configuração, um construto como este seria uma espécie de OK, embora usar reflexão para obter o tipo que corresponde ao nome e instanciá-lo usando essa informação seria uma opção melhor.

No entanto, você deve criar uma classe de fábrica dedicada, desamarrada da hierarquia de classes de animais e retornar uma interface IAnimal em vez de um tipo de base. Então se tornaria útil, você teria conseguido algum desacoplamento.

    
por 13.10.2018 / 08:10
fonte
0

Esta pergunta é oportuna para mim - eu estava escrevendo quase exatamente esse código ontem. Apenas substitua "Animal" pelo que for relevante em meu projeto, embora eu continue com "Animal" por causa de discussão aqui. Em vez de uma instrução 'switch', eu tive uma série um pouco mais complexa de declarações 'if', envolvendo mais do que apenas comparar uma variável com certos valores fixos. Mas isso é um detalhe. Um método de fábrica estática parecia uma maneira simples de projetar as coisas, já que o design surgiu da refatoração de uma bagunça de código rápida e suja.

Eu rejeitei este projeto com base na classe base tendo conhecimento da classe derivada. Se as classes LandAnimal e SeaAnimal forem pequenas, claras e fáceis, elas podem estar no mesmo arquivo de origem. Mas eu tenho grandes métodos confusos para ler arquivos de texto que não estão em conformidade com padrões oficialmente definidos - eu quero minha classe LandAnimal em seu próprio arquivo de origem.

Isso leva à dependência de arquivos circulares - LandAnimal é derivado de Animal, mas Animal precisa saber que LandAnimal, SeaAnimal e outras quinze classes existem. Eu tirei o método de fábrica, coloquei em seu próprio arquivo (no meu aplicativo principal, não na minha biblioteca Animals). Ter um método de fábrica estático parecia bonitinho e inteligente, mas percebi que ele não resolveu nenhum problema de design.

Não tenho idéia de como isso se relaciona com o C # idiomático, já que mudo bastante as linguagens, geralmente ignoro expressões idiomáticas e convenções peculiares a idiomas e stacks de desenvolvimento fora do meu trabalho habitual. Se alguma coisa meu c # pode parecer "pythonic" se isso for significativo. Eu aponto para clareza geral.

Além disso, não sei se há uma vantagem em usar o método de fábrica estática no caso de classes pequenas e simples que provavelmente não serão estendidas em trabalhos futuros - ter tudo isso em um arquivo de origem pode ser bom em alguns casos.

    
por 12.10.2018 / 22:43
fonte