79 votes

Quelle est la bonne alternative à la méthode statique de l'héritage?

Je comprends que la méthode statique de l'héritage n'est pas pris en charge en C#. J'ai aussi lu un certain nombre de discussions (y compris ici) dans lequel les développeurs affirment la nécessité de cette fonctionnalité, à laquelle la réponse typique est "si vous avez besoin d'membre statique de l'héritage, il y a une faille dans votre conception".

OK, étant donné que la programmation orientée objet ne veut pas que j'y pense même héritage statique, je dois conclure que mon apparente besoin de points pour une erreur dans mon design. Mais, je suis coincé. Je voudrais vraiment l'apprécier un peu d'aide de la résolution de cette. Voici le défi ...

Je veux créer une classe de base abstraite (un Fruit) qui encapsule certains complexes de code d'initialisation. Ce code ne peut pas être placé dans le constructeur, puisque certains de il va s'appuyer sur les appels de méthode.

Les fruits seront héritées par d'autres classes concrètes (Pomme, Orange), dont chacun doit exposer un standard de l'usine de la méthode CreateInstance() pour créer et initialiser une instance.

Si le membre statique de l'héritage était possible, je mets en place l'usine de la méthode dans la classe de base et de l'utilisation d'une méthode virtuelle appel à la classe dérivée pour obtenir le type de qui un béton instance doit être initialisé. Le code du client serait simple invoquer Apple.CreateInstance() pour obtenir une entièrement initialisé Apple instance.

Mais clairement, ce n'est pas possible, si quelqu'un peut expliquer comment mes besoins de conception de changer pour répondre à la même fonctionnalité.

59voto

Matt Hamsmith Points 2285

Une idée:

public abstract class Fruit<T>
    where T : Fruit<T>, new()
{
    public static T CreateInstance()
    {
        T newFruit = new T();
        newFruit.Initialize();  // Calls Apple.Initialize
        return newFruit;
    }

    protected abstract void Initialize();
}

public class Apple : Fruit<Apple>
{
    protected override void Initialize() { ... }
}

Et d'appeler de la sorte:

Apple myAppleVar = Fruit<Apple>.CreateInstance();

Pas de supplément à l'usine de classes nécessaires.

17voto

Frederik Gheysels Points 36354

Déplacer la méthode de fabrique de la type, et de le mettre dans sa propre Usine de fabrication de classe.

public abstract class Fruit
{
    protected Fruit() {}

    public abstract string Define();

}

public class Apple : Fruit
{
    public Apple() {}

    public override string Define()
    {
         return "Apple";
    }
}

public class Orange : Fruit
{
    public Orange() {}

    public override string Define()
    {
         return "Orange";
    }
}

public static class FruitFactory<T> 
{
     public static T CreateFruit<T>() where T : Fruit, new()
     {
         return new T();
     }
}

Mais, comme je suis à la recherche à présent, il n'y a pas besoin de déplacer la méthode de création de sa propre Usine de fabrication de classe (bien que je pense qu'il est préférable de séparation des préoccupations, vous pouvez le mettre dans le Fruit de la classe:

public abstract class Fruit
{

   public abstract string Define();

   public static T CreateFruit<T>() where T : Fruit, new()
   {
        return new T();
   }

}

Et, pour voir si ça fonctionne:

    class Program
    {
        static void Main( string[] args )
        {
            Console.WriteLine (Fruit.CreateFruit<Apple> ().Define ());
            Console.WriteLine (Fruit.CreateFruit<Orange> ().Define ());

            Console.ReadLine ();
        }        
    }

5voto

John Gietzen Points 23645

Comment cette forme?:

FruitFactory<Apple>.CreateInstance()

L'usine de la classe créée comme ceci:

public static class FruitFactory<T> where T : Fruit, new()
{
    public static T CreateInstance()
    {
        return new T();
    }
}

4voto

Bob Points 34449

Je voudrais faire quelque chose comme ceci

 public abstract class Fruit() {
      public abstract void Initialize();
 }

 public class Apple() : Fruit {
     public override void Initialize() {

     }
 }

 public class FruitFactory<T> where T : Fruit, new {
      public static <T> CreateInstance<T>() {
          T fruit = new T();
          fruit.Initialize();
          return fruit;  
      }
 } 


var fruit = FruitFactory<Apple>.CreateInstance()

4voto

Daniel Rodriguez Points 1069

Pourquoi ne pas créer une usine de classe (modélisé) avec une méthode de création?

FruitFactory<Banana>.Create();

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X