4 votes

Meilleure pratique de conception - un objet doit-il posséder ce qui est passé à son constructeur?

J'ai la classe suivante:

public class SqlCeEventStore: EventStore
{
  private EventStoreDB db;

  public SqlCeEventStore(EventStoreDB db)
  {
    this.db = db;
  }

  public void Dispose()
  {
    db.Dispose();
  }
}

Mon problème est le suivant : est-ce que je fais bien de disposer de l'EventStoreDB dans la méthode Dispose de ma classe, étant donné qu'il a été passé dans le constructeur (et donc, pourrait éventuellement être réutilisé après que ma classe ait été disposée) ?

C'est-à-dire, si je le dispose, je dicte que l'utilisation correcte de ma classe est :

using (var store = new SqlCeEventStore(new EventStoreDB)){
{
  //...
}

mais je peux voir cet appel alternatif être utilisé :

using (var db = new EventStoreDB())
using (var store = new SqlCeEventStore(db))
{
  //...
}

dans ce cas, je ne devrais pas disposer de l'EventStoreDB depuis la classe SqlCeEventStore.

Y a-t-il des arguments pour l'un ou l'autre style ? Je veux en choisir un et m'y tenir, et je préférerais ne pas lancer une pièce :)

2voto

Nrj Points 2788

En général, il n'y a pas de règle à cela, mais oui, je conviendrais que puisque l'objet a été créé en dehors de votre portée et vous a été transmis, vous n'en êtes pas propriétaire.

Si vous l'aviez créé, alors vous auriez tous les droits de faire ce que vous voulez (en documentant le comportement attendu pour les appelants)

C'est classique composition vs agrégation trucs.

1voto

Spencer Rose Points 566

Si l'EventStoreDB appartient à SqlEventStore (c'est-à-dire qu'il fait partie de sa composition), il doit être construit ou fusionné avec la classe SqlEventStore.

S'il est utilisé en dehors de la durée de vie de SqlEventStore, il doit être créé et libéré par le code externe.

1voto

Håvard S Points 11152

Il n'y a pas de règle générale ici, et à mon avis, il ne devrait pas y en avoir une non plus. Les différents objets ont des durées de vie différentes, et la ligne directrice la plus générale serait de s'assurer que les objets sont gérés de manière cohérente en fonction de leur durée de vie, et que les durées de vie sont aussi courtes que possible.

Vous pouvez essayer d'utiliser ce qui suit comme ligne directrice (mais n'ayez pas peur de dévier quand vous en avez besoin) : Éliminez un objet dans le même contexte que celui où vous l'avez alloué. Cette directive est adaptée à de nombreux scénarios, et c'est exactement ce que l'instruction using simplifie.

Si vous avez des objets à longue durée de vie sans point d'élimination évident, ne vous inquiétez pas. C'est normal. Cependant, demandez-vous ceci : Ai-je vraiment besoin que cet objet vive aussi longtemps qu'il le fait ? Y a-t-il une autre façon dont je peux modéliser ceci pour raccourcir la durée de vie ? Si vous pouvez trouver une autre solution qui raccourcit la durée de vie, cela rend généralement l'objet plus gérable et devrait être préféré.

Mais encore une fois, il n'y a pas de "règle vraie" ici.

0voto

Sherif elKhatib Points 23987

Vous ne pouvez pas en choisir un et vous y tenir. L'utilisateur peut toujours choisir ce qu'il veut.

Cependant, gardez à l'esprit que vous n'êtes pas responsable en tant que classe de disposer des objets passés par le constructeur.


note

La suite est vraiment ridicule à discuter car si vous voulez imposer l'initialisation de la classe en utilisant *new SqlCeEventStore(new EventStoreDB))* alors pourquoi ne pas supprimer ce paramètre EventStoreDB et instancier la variable db à l'intérieur de votre constructeur.

Workaround

Il existe un contournement - vérifiez ceci:

public myClass {
    // ne rendez pas le constructeur public //cachez-le
    private myClass(EventStoreDB db){
        this.db = db;
    }
    // créez un constructeur public qui appellera le privé de la manière souhaitée
    public myClass(){
        this(myClass(new EventStoreDB()));
    }
}

0voto

supercat Points 25534

Je suggérerais que si l'on peut raisonnablement imaginer des situations dans lesquelles l'objet construit serait la dernière chose dans l'univers qui s'intéresse à l'objet passé en paramètre, ainsi que des situations dans lesquelles d'autres choses voudront continuer à utiliser l'objet passé en paramètre après que le constructeur en ait fini avec lui, il peut être souhaitable d'avoir un paramètre de constructeur qui spécifie si le nouvel objet doit prendre possession de l'objet qui a été passé en paramètre.

Remarquez que si l'objet construit va prendre possession de l'objet passé en paramètre, il est important de s'assurer que l'objet sera libéré même si le constructeur lance une exception. Une façon de faire cela serait d'encapsuler l'appel au constructeur dans une routine qui, dans un bloc "enfin", libérera l'objet passé en paramètre à moins que le constructeur ne se soit achevé avec succès.

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