Classi di base come fabbriche?

14

Durante il weekend stavo scrivendo del codice e mi sono ritrovato a voler scrivere una factory come metodo statico in una classe base.

La mia domanda è semplicemente sapere se questo è un approccio idematico c #?

La mia sensazione che potrebbe non provenire dal fatto che la classe base abbia conoscenza della classe derivata.

Detto questo, non sono sicuro di un modo più semplice per ottenere lo stesso risultato. Un'intera classe di fabbrica sembra (almeno per me) come una complessità non necessaria (?)

Qualcosa come:

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

5 risposte

13

Bene, il vantaggio di una classe factory separata è che può essere preso in giro nei test unitari.

Ma se non lo farai o lo trasformerai in polimorfismo in altro modo, allora un metodo Factory statico sulla classe stessa è OK.

    
risposta data 05.03.2012 - 17:20
fonte
18

Potresti usare Generics per evitare l'istruzione switch e disaccoppiare le implementazioni downstream anche dalla classe base.

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

Utilizzo:

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

o

 var rabbit = Animal.CreateAnimal<LandAnimal>(); 
    
risposta data 05.03.2012 - 17:36
fonte
5

Portato all'estremo, la fabbrica potrebbe essere anche generica.

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

Quindi è possibile creare qualsiasi tipo di fabbrica di oggetti, che a loro volta potrebbero creare qualsiasi tipo di oggetto. Non sono sicuro che sia più semplice, è sicuramente più generico.

Non vedo nulla di sbagliato in un'istruzione switch per un'implementazione di una piccola fabbrica. Una volta che hai un numero elevato di oggetti o possibili gerarchie di classi diverse, penso che un approccio più generico sia più adatto.

    
risposta data 05.03.2012 - 19:05
fonte
1

Cattiva idea. In primo luogo, viola il principio aperto-chiuso. Per ogni nuovo animale dovresti fare di nuovo casino con la tua classe base e potresti potenzialmente romperlo. Le dipendenze andrebbero nella direzione sbagliata.

Se hai bisogno di creare animali da una configurazione, un costrutto come questo sarebbe un po 'OK, sebbene usare il reflection per ottenere il tipo che corrisponde al nome e istanziarlo usando le informazioni sul tipo ottenuto sarebbe una soluzione migliore.

Ma dovresti comunque creare una classe factory dedicata, slegata dalla gerarchia delle classi animali e restituire un'interfaccia IAnimal piuttosto che un tipo base. Allora sarebbe utile, avresti ottenuto qualche disaccoppiamento.

    
risposta data 13.10.2018 - 08:10
fonte
0

Questa domanda è puntuale per me - stavo scrivendo quasi esattamente tale codice ieri. Basta sostituire "Animal" con qualsiasi cosa sia rilevante nel mio progetto, anche se rimarrò con "Animal" per il gusto di discutere qui. Invece di un'istruzione "switch", ho avuto una serie un po 'più complessa di istruzioni "if", che coinvolgono molto più del semplice confronto di una variabile con determinati valori fissi. Ma questo è un dettaglio. Un metodo statico di fabbrica mi è sembrato un modo pulito di progettare le cose, dal momento che il design è emerso dal refactoring dei precedenti fastidiosi pasticci di codice.

Ho respinto questo disegno sulla base della classe base che ha conoscenza della classe derivata. Se le classi LandAnimal e SeaAnimal sono piccole, ordinate e semplici, possono trovarsi nello stesso file sorgente. Ma ho grandi metodi disordinati per leggere i file di testo non conformi agli standard definiti ufficialmente - Voglio la mia classe LandAnimal nel proprio file sorgente.

Ciò porta alla dipendenza circolare dei file - LandAnimal è derivato da Animal, ma Animal deve sapere già che LandAnimal, SeaAnimal e quindici altre classi esistono. Ho tirato fuori il metodo factory, l'ho messo nel suo file (nella mia applicazione principale, non nella mia libreria Animals) Avere un metodo statico di fabbrica mi sembrava carino e intelligente, ma mi sono reso conto che in realtà non risolveva alcun problema di progettazione.

Non ho idea di come questo si riferisca al C # idiomatico, dal momento che cambio molto linguaggio, di solito ignoro idiomi e convenzioni peculiari di lingue e stack di sviluppo al di fuori del mio solito lavoro. Semmai la mia C # potrebbe sembrare "pitonica" se ciò è significativo. Mirare alla chiarezza generale.

Inoltre, non so se ci sarebbe un vantaggio nell'usare il metodo statico di fabbrica nel caso di classi piccole e semplici che difficilmente verranno estese in futuro: avere tutto in un unico file sorgente potrebbe essere bello in alcuni casi.

    
risposta data 12.10.2018 - 22:43
fonte

Leggi altre domande sui tag