6
votes

Est-il possible de créer une classe dérivée à partir d'un constructeur de classe de base?

J'ai dit 3 classes, animal, chat et chien.

// calling code
var x = new Animal("Rex"); // would like this to return a dog type
var x = new Animal("Mittens"); // would like this to return a cat type

if(x.GetType() == typeof(Dog))
{
   x.Bark();
}
else
{
  x.Meow();
}


class Animal
{
   public Animal(string name)
   {
      // check against some list of dog names ... find rex
      // return Animal of type Dog.

      // if not...

      // check against some list of cat names ... find mittens
      // return Animal of type Cat.
   }
}


1 commentaires

Pas réellement sans vous limiter ... Votre classe de base devrait connaître ses sous-classes, ce qui n'est pas très utile.


4 Réponses :


9
votes

Ce que vous cherchez est soit un «constructeur virtuel» (pas possible dans C #), soit le motif d'usine.

class Animal
{
   // Factory method
   public static Animal Create(string name)
   {
      Animal animal = null;
      ...  // some logic based on 'name'
          animal = new Zebra();

      return animal;
   }
}


0 commentaires

5
votes

Non. Fondamentalement, le bon correctif consiste à utiliser une méthode statique pouvant créer une instance du type droit: xxx

ou ceci pourrait être une méthode instance dans un AnimalFactory type (ou autre). Ce serait une approche plus extensible - l'usine pourrait implémenter une interface, par exemple et pourrait être injectée dans la classe qui devait créer les instances. Cela dépend vraiment du contexte, parfois, cette approche est trop excédée.

Fondamentalement, un nouveau foo (...) appel toujours crée une instance de exactement foo . Alors qu'une méthode statique déclarée avec un type de retour de FOO peut renvoyer une référence à n'importe quel type compatible avec FOO .


0 commentaires

1
votes

Non, je ne pense pas que cela soit possible dans la manière dont vous voulez.

Vous pouvez créer une classe statique qui a une méthode qui renvoie un animal basé sur un nom, par exemple P>

static Animal CreateAnimal(string name)
{
    if(catList.Contains(name))
        return new Cat(name");
    else if(dogList.Contains(name))
        return new Dog(name);

    return null;
}


0 commentaires

0
votes

Les autres réponses montrent que vous devez utiliser un motif d'usine, mais je voulais vous donner un exemple plus "pratique" de la façon dont vous le feriez. J'ai fait exactement ce que vous avez fait, mais je travaillais avec le imprimante EPL2 Langue . Quand j'ai vu x code>, je devais créer une instance de classe rectangle code>, quand j'ai vu a code> je devais créer une instance de classe Texte code>.

(J'ai écrit ce Il y a longtemps donc je suis Bien sûr, certaines des choses que j'ai pouvais être améliorées sur). p> xxx pré>

la manière dont le code fonctionne est que j'utilise le singleton modèle pour créer un classe d'usine afin que les gens puissent appeler var commande = epl2commandfactory.instance.createepl2command ("...") code>; en passant dans la chaîne de commande EPL2 et renvoie une instance de la classe qui représente cette classe spécifique. p>

Lors de l'initialisation, j'utilise la réflexion pour trouver des classes prenant en charge l'interface IEPL2GeneralFactoryProduise code>, si le La classe prend en charge l'interface de l'usine stocke le code d'un ou deux lettres représentant la commande d'imprimante dans un dictionnaire de types. p>

Lorsque vous essayez de créer la commande L'usine lève la commande d'imprimante dans le dictionnaire et crée le Classe correcte, il transmet ensuite la chaîne de commande complète sur cette classe pour un traitement ultérieur. P>

Voici une copie d'une classe de commande et ses parents si vous vouliez le voir P>

rectangle code>: p> xxx pré>

drawableItembase code>: p> xxx pré>

EPL2CommandBase Code>: P>

public interface IEpl2GeneralFactoryProduct
{
    string GetFactoryKey();
}
public interface IEpl2Command
{
    string CommandString { get; set; }
}

public interface IDrawableCommand : IEpl2Command
{
    void Paint(System.Drawing.Graphics g, System.Drawing.Image buffer);
}


0 commentaires