2013-05-30 7 views
1

Voici un pseudo-code pour illustrer ce que je regarde.Héritage et classes dans les classes

public class Loader 
{ 
    public Execute() 
    { 
     var currentPage = new ItemPageDocumentBuilder(); 
     while(reader.Read()) 
     { 
      currentPage.Add(reader.XmlDoc); 
     } 
    } 

    private class ItemsToLoad 
    { 
     private XmlDocument _page 
     public void Add(XmlElement itemelement) 
     { 
      _page.DocumentElement.AppendChild(itemElement); 
     } 
    } 
} 

J'ai besoin de dériver une classe de chargeur, puis remplacer la méthode Add de la classe ItemsToLoad à l'intérieur, puis appelez base.Execute(). En d'autres termes, je veux que la méthode Execute() de ma classe dérivée soit exactement la même que celle de Loader, mais utilise la méthode Add substituée de ItemsToLoad pour son travail.

Je pense que la façon la plus simple de faire cela serait de supprimer ItemsToLoad de l'intérieur de Loader, et de le rendre abstrait, correct?

Si je ne pouvais pas faire cela, par intérêt, quelle est la meilleure solution?

+0

Vous pouvez également injecter un composant ItemLoader dans Loader au lieu d'utiliser une classe interne privée. –

Répondre

1

Si je comprends bien vos besoins, vous avez deux responsabilités: exécuter quelque chose (ce qui est toujours le même), et en ajoutant quelque chose (ce qui est différent).

Je le ferais beaucoup plus simple, sans héritages et classes internes.

Pour la tâche d'ajouter, vous définissez une interface:

public interface IItemAdder 
{ 
    void Add(); 
} 

Et plusieurs implémentations:

public class ItemAdder1 : IItemAdder 
{ 
    public void Add() 
    {    
     // specific implementation here 
    } 
} 

Ensuite, vous avez un chargeur, dans lequel vous injectez une instance spécifique de l'article aspic

public class Loader : ILoader 
{ 
    private IItemAdder _itemAdder; 
    public Loader(IItemAdder itemAdder) 
    { 
     _itemAdder = itemAdder; 
    } 
    public void Execute() 
    { 
     // use injected item adder to do work 
     _itemAdder.Add(); 
    }  
} 

public interface ILoader 
{ 
    void Execute(); 
} 

Et si l'utilisation est:

var loader = new Loader(new ItemAdder1()); 
loader.Execute();  

De cette façon, tout est injecté, peut être remplacé et raillé facilement; et vous séparez clairement les préoccupations.

+0

Merci. J'ai pris cette route à la fin, bien que j'ai ajouté la collection Interfaced comme propriété virtuelle et l'ai passée au dessus plutôt que de l'injecter. –

+0

La raison pour laquelle le constructeur est une meilleure solution est que vous définissez clairement les dépendances nécessaires, donc vous les connaissez au préalable et vous devez les injecter lors de la création de l'instance de votre classe. Avec l'injection de propriété, il n'est pas si clair que c'est une dépendance. –

+0

Oui, j'apprécie que ce soit un bon conseil. Mais dans ce cas, il aurait brisé trop d'architecture dépendante pour changer le constructeur. Il a été étiqueté pour le refactoring plus tard maintenant le problème actuel est résolu :) –

0

Voici une suggestion (syntaxe pourrait ne pas être correcte si):

public class Loader 
{ 
    ItemsToLoad item; 
    public Loader(ItemsToLoad item) { 
     this.item = item; 
    } 

    public Execute() 
    { 
     // do things using item like item.add(); 
    } 
} 

interface ItemsToLoad 
{ 
    void add(); 
} 

class ItemsToLoad1: ItemsToLoad 
{ 
    void add(){ 
     // implementation 
    } 
} 

class ItemsToLoad2: ItemsToLoad 
{ 
    void add(){ 
     // implementation 
    } 
} 

Et voici comment les utiliser;

ItemsToLoad item; 
if (some condition) { 
    item = new ItemsToLoad1() 
} else { 
    item = new ItemsToLoad2() 
} 

Loader loader = new Loader(item); 
loader.execute(); 
0

Vous pouvez hériter des deux classes et injecter l'objet de sous-classe enfant à son parent.

class Loader 
    { 

     public void Execute(ItemsToLoad argObj) 
     { 
      if(argObj == null) 
       argObj = new ItemsToLoad(); 

      argObj.Add(19); 
     } 

     public class ItemsToLoad 
     { 
      public virtual void Add(int a) 
      { 
       Console.WriteLine("Reached ItemsToLoad."); 
      } 
     } 
    } 

class ChildLoader:Loader 
    { 
     public void Execute(ItemsToLoad argObjLoader) 
     { 
      if (argObjLoader == null) 
       argObjLoader = new ChildItemsToLoad(); 

      base.Execute(argObjLoader); 
    } 

    class ChildItemsToLoad : Loader.ItemsToLoad 
    { 

     public override void Add(int b) 
     { 
      Console.WriteLine("Reached ChildItemsToLoad."); 
     } 

    } 
} 

Et peut commencer par

ChildLoader obj999 = new ChildLoader(); 
obj999.Execute(null); 
0

Je dois dériver une classe à partir de Loader, puis remplacer la méthode Add de la classe ItemsToLoad à l'intérieur, puis appeler base.Execute(). En d'autres termes, je veux que la méthode Execute() de ma classe dérivée soit exactement la même que celle de Loader, mais utilise la méthode Add substituée de ItemsToLoad pour son travail.

Vous devez remplacer Loader, et non ItemsToLoad. Vous n'avez pas montré le code qui utilise ItemsToLoad, il est donc difficile d'être spécifique - mais à tout le moins, vous devez remplacer le new ItemsToLoad pour pointer vers votre sous-classe. En outre, ItemsToLoad est privé - ce qui signifie que vous ne pouvez pas l'utiliser sauf depuis Loader.Comme il est maintenant, vous auriez besoin d'un complètement réécrit ItemsToLoad et de remplacer toutes les méthodes dans Loader qui utilise ItemsToLoad.

Si vous contrôlez la classe Loader, les modifications les plus simples consisteraient probablement à supprimer la création de ItemsToLoad et à ouvrir ItemsToLoad afin de pouvoir la sous-classer. Quelque chose comme:

public class Loader { 
    private ItemsToLoad Items { get; set; } 

    protected virtual ItemsToLoad CreateItemsToLoad() { 
     return new ItemsToLoad(); 
    } 

    protected class ItemsToLoad { 
     public virtual void Add() { 
     } 
    } 
} 

public class MyOtherLoader : Loader { 
    protected override ItemsToLoad CreateItemsToLoad() { 
     return new MyOtherItemsToLoad(); 
    } 

    private class MyOtherItemsToLoad : ItemsToLoad { 
     public override void Add() { 
     } 
    } 
} 
Questions connexes