Gardez vos objets dans un état consistent

Julien on avr 12th 2008

Une part d'un bon design orienté objet est de s'assurer que ses objets sont toujours dans un état correct.

Par exemple, dans le monde de la finance, nous avons des instruments financiers appelés "Dérivés". D'après Wikipedia:

Un produit dérivé est un instrument financier dont la valeur fluctue en fonction de l'évolution du taux ou du prix d'un produit appelé sous-jacent.

Par conséquent, dans le monde réel, un produit dérivé ne peut exister sans la présence du produit sous-jacent. Un future sur le CAC 40 n'aurait pas pu être créé sans que le CAC 40 existe auparavant. Si nous voulons représenter un produit dérivé dans une application, nous devons donc nous assurer que nous suivons la même règle.

Assumons que nous avons la classe suivante:

  1. class Derivative
  2. {
  3. private string _name;
  4. private Instrument _underlyingInstrument ;
  5.  
  6. public string Name
  7. {
  8. get { return _name; }
  9. }
  10.  
  11. public Instrument UnderlyingInstrument
  12. {
  13. get { return _underlyingInstrument; }
  14. }
  15.  
  16. public Derivative(string name, Instrument underlyingInstrument)
  17. {
  18. _name = name;
  19. _underlyingInstrument = underlyingInstrument;
  20. }
  21. }

Un nouveau développeur arrivant sur un projet associera notre classe Derivative au concept financier associé. A priori, il n'aura pas besoin de regarder le code de la classe et il s'attendra à ce que la propriété UnderlyingInstrument retourne un objet non-null. Cependant, l'implémentation courante de le garanti pas. En réalité, cette classe peut actuellement être utilisé pour véhiculer le nom d'un dérivé sans l'associer à son produit sous-jacent. Si nous voulions faire cela, nous devrions alors créer une nouvelle classe dans ce but uniquement. En attendant, si nous voulons que notre code reste dans un état maintenable, nous devons nous assurer que chaque objet de type Derivative sera construit correctement. Sans cela, chaque personne pourra faire un usage différent et potentiellement incompatible de la classe.

Dans le cas présent, s'assurer que notre objet est dans un état correcte peut se faire très facilement. Nous devons juste appliquer une pincée de "Design By Contract". Notre constructeur deviendra alors:

  1. public Derivative(string name, Instrument underlyingInstrument)
  2. {
  3. if(name == null || name.Length == 0)
  4. {
  5. throw new Exception("The name of the derivative can't be null or empty");
  6. }
  7. else if(underlyingInstrument == null)
  8. {
  9. throw new Exception("A derivative must have an underlying instrument");
  10. }
  11.  
  12. _name = name;
  13. _underlyingInstrument = underlyingInstrument ;
  14. }

Maintenant, nous sommes certain qu'un collègue développeur ne va pas utiliser la classe de façon étrange :)

Évidemment, il est possible d'améliorer cet exemple de façon significative avec différents frameworks et techniques (ce qui inclus l'appel à Debug.Assert ou le développement de sa propre classe d'assertion). Par exemple, J'écrirai idéalement le code de la façon suivante:

  1. public Derivative(string name, Instrument underlyingInstrument )
  2. {
  3. Guard.Against(name == null, "The name of the derivative can't be null");
  4. Guard.Against(name.Length == 0, "The name of the derivative can't be empty");
  5. Guard.Against(underlyingInstrument == null, "The underlying instrument of the derivative can't be null");
  6.  
  7. _name = name;
  8. _underlyingInstrument = underlyingInstrument;
  9. }

Mais c'est un sujet pour un autre billet!

Filed in Alt.net Foundations | No responses yet

Trackback URI | Comments RSS

Leave a reply