Bibliobrol : Observer pattern

Nous avons souvent besoin de contrôler le travail effectué par les méthodes des différentes classes de notre application. Nous allons donc créer une classe Notification, qui nous permettra de placer différentes informations qui nous renseigneront sur les différentes opérations effectuées dans l'application :

  • sender : un objet qui nous permet de déterminer quelle est la classe qui lance une notification.
  • title : une courte chaîne de caractères.
  • msg : le message qui est envoyé
  • e : une exception qui nous permet de déterminer à quelle ligne de quelle classe se situe l'erreur, le message d'erreur, la trace pour remonter le cours des évènements qui ont conduit à l'erreur, etc.
  • verbose : le niveau de notification
  1. using System;
  2.  
  3. namespace be.gaudry.observer
  4. {
  5. public class Notification
  6. {
  7. #region declarations
  8. /// <summary>
  9. /// Level of notification. May be used to deal only with some notifications.
  10. /// </summary>
  11. public enum VERBOSE
  12. {
  13. /// <summary>
  14. /// sql query or another persistence operation
  15. /// </summary>
  16. persistentOperation,
  17. /// <summary>
  18. /// any operation
  19. /// </summary>
  20. basicOperation,
  21. /// <summary>
  22. /// feedback of an operation
  23. /// </summary>
  24. opsResult,
  25. /// <summary>
  26. /// requests syntax to debug
  27. /// </summary>
  28. advancedOperation,
  29. /// <summary>
  30. /// info to debug
  31. /// </summary>
  32. debug,
  33. /// <summary>
  34. /// any general error
  35. /// </summary>
  36. error,
  37. /// <summary>
  38. /// may not interrupt application
  39. /// </summary>
  40. lowError,
  41. /// <summary>
  42. /// application must be interrupt
  43. /// </summary>
  44. criticalError,
  45. /// <summary>
  46. /// used to notify without display info
  47. /// </summary>
  48. internalNotification,
  49. /// <summary>
  50. /// used to notify a modification without display info
  51. /// </summary>
  52. modified,
  53. /// <summary>
  54. /// used to store errors and not display it
  55. /// </summary>
  56. hideErrors,
  57. /// <summary>
  58. /// used to clean stored errors and adopt normal behaviour
  59. /// </summary>
  60. showNewErrors,
  61. /// <summary>
  62. /// used to display stored errors
  63. /// </summary>
  64. showErrors
  65. }
  66.  
  67. private String title, msg;
  68. private Exception e;
  69. private VERBOSE verbose;
  70. private Object sender;
  71. #endregion
  72.  
  73. #region constructors
  74. public Notification(String msg)
  75. : this(VERBOSE.basicOperation, "Information", msg) { }
  76.  
  77. public Notification(String msg, Object sender)
  78. : this(VERBOSE.basicOperation, "Information", msg, sender) { }
  79.  
  80. public Notification(String title, String msg)
  81. : this(VERBOSE.basicOperation, title, msg) { }
  82.  
  83. public Notification(String title, String msg, Object sender)
  84. : this(VERBOSE.basicOperation, title, msg, sender) { }
  85.  
  86. public Notification(VERBOSE level, String title, String msg, Object sender)
  87. : this(level, title, msg)
  88. {
  89. this.sender = sender;
  90. }
  91.  
  92. public Notification(VERBOSE level, String msg, Object sender)
  93. : this(level, "", msg, sender) { }
  94.  
  95. public Notification(VERBOSE level, String title, String msg)
  96. {
  97. this.verbose = level;
  98. this.title = title;
  99. this.msg = msg;
  100. }
  101.  
  102. public Notification(VERBOSE level, String title, String msg, Exception e)
  103. : this(level, title, msg)
  104. {
  105. this.e = e;
  106. }
  107.  
  108. public Notification(VERBOSE level, String title, String msg, Exception e, Object sender)
  109. : this(level, title, msg, e)
  110. {
  111. this.sender = sender;
  112. }
  113.  
  114. public Notification(VERBOSE level, Exception e)
  115. : this(level, "Erreur", "", e) { }
  116.  
  117. public Notification(VERBOSE level, Exception e, Object sender)
  118. : this(level, "Erreur", "", e, sender) { }
  119.  
  120. public Notification(VERBOSE level, String title, Exception e)
  121. : this(level, title, "", e) { }
  122.  
  123. public Notification(VERBOSE level, String title, Exception e, Object sender)
  124. : this(level, title, "", e, sender) { }
  125.  
  126. public Notification(Exception e)
  127. : this(VERBOSE.error, "Erreur", "", e) { }
  128.  
  129. public Notification(Exception e, Object sender)
  130. : this(VERBOSE.error, "Erreur", "", e, sender) { }
  131. #endregion
  132.  
  133. #region getters and setters
  134. public String Title
  135. {
  136. set { this.title = value; }
  137. get { return this.title; }
  138. }
  139. public String Msg
  140. {
  141. set { this.msg = value; }
  142. get { return this.msg; }
  143. }
  144. public Exception NotificationException
  145. {
  146. set { this.e = value; }
  147. get { return this.e; }
  148. }
  149. public VERBOSE Level
  150. {
  151. set { this.verbose = value; }
  152. get { return this.verbose; }
  153. }
  154. public Object Sender
  155. {
  156. set { this.sender = value; }
  157. get { return this.sender; }
  158. }
  159. #endregion
  160. }
  161. }

Nous allons récupérer ces notifications, et les afficher dans notre console.

  • Donc, nous pouvons envoyer directement nos notifications à la console ?

Non. Si nous décidons par la suite d'afficher les notifications dans un autre composant, ou de ne pas utiliser notre console, nous devrions modifier le code dans toutes les classes, à chaque fois que nous lançons une notification.

Le pattern observer vient à notre aide dans ce cas. Nous pouvons utiliser les délégués (une très bonne pratique du C#), mais nous allons ici calquer au plus près le pattern et réimplémenter nos classes.

C'est à la classe qui contient les méthodes à surveiller que revient la responsabilité de signaler les modifications. Comme il est impensable que le modèle connaisse la vue, les classes de la vue qui souhaitent être averties des modifications (Observer, ou observateur) doivent s'enregistrer auprès de la classe qui signale (Observable).

  1. using System;
  2. using System.Collections.Generic;
  3.  
  4. namespace be.gaudry.observer
  5. {
  6. /// <summary>
  7. /// Provides methods to add or remove observers and notify them
  8. /// </summary>
  9. [Serializable]
  10. public class Observable : IObservable
  11. {
  12. private List<IObserver> observers = new List<IObserver>();
  13.  
  14. #region IObservable Members
  15.  
  16. /// <summary>
  17. /// Send a notification to all registerd obervers
  18. /// </summary>
  19. /// <param name="notification">notification to send</param>
  20. public void notify(Notification notification)
  21. {
  22. try
  23. {
  24. foreach (IObserver observer in observers)
  25. {
  26. try
  27. {
  28. observer.update(notification);
  29. }
  30. catch (Exception) { }
  31. }
  32. }
  33. catch (InvalidOperationException) { }
  34. }
  35.  
  36. /// <summary>
  37. /// Add (register) an observer
  38. /// </summary>
  39. /// <param name="o">observer to add</param>
  40. public void addObserver(IObserver o)
  41. {
  42. if(!observers.Contains(o)) observers.Add(o);
  43. }
  44.  
  45. /// <summary>
  46. /// Remove an observer
  47. /// </summary>
  48. /// <param name="o">observer to remove</param>
  49. public void removeObserver(IObserver o)
  50. {
  51. observers.Remove(o);
  52. }
  53.  
  54. #endregion
  55. }
  56. }

Afin de regrouper toutes les classes qui s'enregistrent, chaque observateur devra implémenter l'interface IObserver, qui l'oblige à implémenter une méthode update qui effectue un traitement ou non en fonction de l'évènement signalé. Nous allons donc forcer la méthode à prendre un argument qui sera une instance de la classe Notification.

  1. namespace be.gaudry.observer
  2. {
  3. public interface IObserver
  4. {
  5. void update(Notification notification);
  6. }
  7. }

Notre observable devra parcourir la collection d'observateur, et signaler l'évènement à chacun en appelant leur méthode update. Nous nommerons cette méthode notify.
De plus, l'observable doit fournir 2 méthodes pour ajouter et enlever un observateur.

  1. namespace be.gaudry.observer
  2. {
  3. /// <summary>
  4. /// Defines methods witch must be implemented for an observable object
  5. /// </summary>
  6. public interface IObservable
  7. {
  8. /// <summary>
  9. /// Sends a notification to all registerd obervers
  10. /// </summary>
  11. /// <param name="notification">notification to send</param>
  12. void notify(Notification notification);
  13.  
  14. /// <summary>
  15. /// Adds (register) an observer
  16. /// </summary>
  17. /// <param name="o">observer to add</param>
  18. void addObserver(IObserver o);
  19.  
  20. /// <summary>
  21. /// Removes an observer
  22. /// </summary>
  23. /// <param name="o">observer to remove</param>
  24. void removeObserver(IObserver o);
  25. }
  26. }

Nous allons donc créer une interface IObservable, mais aussi une classe Observable. Il suffit qu'une classe hérite d'Observable pour pouvoir diffuser les informations nécessaires. Si la classe hérite déjà d'une autre classe, elle devra alors implémenter l'interface IObservable, qui nous oblige alors à écrire les méthodes nécessaires.

  • Et si un observateur ne connaît pas la classe qu'il désire observer ?

Dans ce cas, l'observateur peut observer la classe singleton StaticObservable, et les classes qui doivent effectuer les notifications peuvent simplement appeler une méthode statique de cette classe.

Cette page contiendra des explications plus détaillées par la suite (quand j'aurais un moment de libre).

  1. namespace be.gaudry.observer
  2. {
  3. /// <summary>
  4. /// Singleton used to add observable features into a class (the observer may not know the class, it must know only this).
  5. /// </summary>
  6. public class StaticObservable
  7. {
  8. #region singleton
  9. private static Observable instance = null;
  10. private static readonly object padlock = new object();
  11. private StaticObservable() { }
  12. /// <summary>
  13. ///
  14. /// </summary>
  15. private static Observable Instance
  16. {
  17. get
  18. {
  19. lock (padlock)
  20. {
  21. if (instance == null)
  22. {
  23. instance = new Observable();
  24. }
  25. return instance;
  26. }
  27. }
  28. }
  29. #endregion
  30.  
  31. #region observable methods
  32. /// <summary>
  33. /// Send a notification to all registerd obervers
  34. /// </summary>
  35. /// <param name="notification">notification to send</param>
  36. public static void notify(Notification notification)
  37. {
  38. StaticObservable.Instance.notify(notification);
  39. }
  40.  
  41. /// <summary>
  42. /// Add (register) an observer
  43. /// </summary>
  44. /// <param name="o">observer to add</param>
  45. public static void addObserver(IObserver o)
  46. {
  47. StaticObservable.Instance.addObserver(o);
  48. }
  49.  
  50. /// <summary>
  51. /// Remove an observer
  52. /// </summary>
  53. /// <param name="o">observer to remove</param>
  54. public static void removeObserver(IObserver o)
  55. {
  56. StaticObservable.Instance.removeObserver(o);
  57. }
  58. #endregion
  59.  
  60. #region static helper methods
  61.  
  62. /// <summary>
  63. /// store errors and not display it
  64. /// </summary>
  65. /// <param name="notification">notification to send</param>
  66. public static void hideErrors()
  67. {
  68. notify(new Notification(Notification.VERBOSE.hideErrors,null));
  69. }
  70.  
  71. /// <summary>
  72. /// display stored errors
  73. /// </summary>
  74. /// <param name="notification">notification to send</param>
  75. public static void showErrors()
  76. {
  77. notify(new Notification(Notification.VERBOSE.showErrors,null));
  78. }
  79.  
  80. /// <summary>
  81. /// lean stored errors and adopt normal behaviour
  82. /// </summary>
  83. /// <param name="notification">notification to send</param>
  84. public static void showNewErrors()
  85. {
  86. notify(new Notification(Notification.VERBOSE.showNewErrors,null));
  87. }
  88. #endregion
  89. }
  90. }

Réseaux sociaux

Vous pouvez modifier vos préférences dans votre profil pour ne plus afficher les interactions avec les réseaux sociaux sur ces pages.

 

Nuage de mots clés

12 mots clés dont 0 définis manuellement (plus d'information...).

Avertissement

Cette page ne possède pas encore de mots clés manuels, ceci est donc un exemple automatique (les niveaux de pertinence sont fictifs, mais les liens sont valables). Pour tester le nuage avec une page qui contient des mots définis manuellement, vous pouvez cliquer ici.

Vous pouvez modifier vos préférences dans votre profil pour ne plus afficher le nuage de mots clés.

 

Astuce pour imprimer les couleurs des cellules de tableaux : http://www.gaudry.be/ast-rf-450.html
Aucun commentaire pour cette page

© Ce document issu de l′infobrol est enregistré sous le certificat Cyber PrInterDeposit Digital Numbertection. Enregistrement IDDN n° 5329-9681
Document créé le 16/12/06 20:32, dernière modification le Mercredi 28 Juin 2017, 14:26
Source du document imprimé : http:///www.gaudry.be/bibliobrol-observer.html
St.Gaudry©07.01.02
Outils (masquer)
||
Recherche (afficher)
Recherche :

Utilisateur (masquer)
Apparence (afficher)
Stats (afficher)
15838 documents
455 astuces.
550 niouzes.
3107 definitions.
447 membres.
8121 messages.

Document genere en :
0,20 seconde

Mises à jour :
Mises à jour du site
Citation (masquer)
La science a-t-elle promis le bonheur? Je ne le crois pas. Elle a promis la vérité, et la question est de savoir si l'on fera jamais du bonheur avec de la vérité.

Emile Zola
 
l'infobrol
Nous sommes le Mercredi 13 Décembre 2017, 00:28, toutes les heures sont au format GMT+1.00 Heure, heure d'hiver