Patrón Observador en .NET - pattern Observer - Jorge Serrano - MVP Visual Developer - Visual Basic

Patrón Observador en .NET - pattern Observer

 

Patrón Observador en .NET - pattern Observer

Introducción

El patrón observador (pattern Observer) es uno de los patrones que más me gustan, motivo principal por el cual me he animado a escribir esta entrada para que lo muestre de una forma práctica, agradable y útil para en primer lugar entenderlo, y posteriormente ser implementado en nuestros desarrollos de .NET.

Espero que esta entrada os ayude a entender mejor el funcionamiento de este patrón y os brinde la posibilidad de valorarlo por si os interesa utilizarlo en vuestros desarrollos, o implementar un híbrido que os resulte útil para abordar determinados problemas con los que os podáis encontrar durante vuestros desarrollos Software.

Visión general del patrón

Este patrón se define como un patrón de tipo relacional de uno a muchos.

De esta forma, un subscriptor (también denominado en algunas ocasiones como observador) es el encargado de subscribirse a un publicador.

El publicador es a su vez el encargado de notificar que ha sucedido “algo” que requiere la atención de sus subscritores.

En este punto, el publicador estará relacionado con todos sus subscriptores, y cuando ocurra “algo”, todos los subscriptores se darán por enterados.

Lógicamente, debe haber un mecanismo que permita agregar un subscriptor y eliminar al subscriptor, tanto para que reciba notificaciones como para que deje de recibirlas.

Aquí tampoco se está analizando la casuística de que con determinados sucesos, el publicador sólo comunique que ha sucedido algo a unos determinados subscriptores y a otros no. Simplemente vamos a analizar el caso general de este patrón en el que todos los subscriptores reciben la comunicación de aviso (notificación) por parte del publicador.

Aproximación 1

Vamos a empezar por lo tanto a preparar nuestra primera implementación del patrón Observador.

Se trata de una implementación generalista.

Es decir, partiremos de la base de crear una biblioteca de clases cuyo proyecto denominaré PatternObserver para crear en él las clases que permitan comprender y utilizar este patrón.

También crearé un proyecto adicional de tipo WinForms que utilizaré para probar la implementación del patrón y demostrar su funcionamiento en esta primera aproximación.

PatternObserver

El diagrama general de lo que vamos a crear es lo que se puede observar en la siguiente imagen:

Aquí podemos observar un proyecto PatternObserver que contendrá las siguientes clases:

-          IObserver

-          ISubject

-          Subject

La explicación de cada una de estas clases es la siguiente:

IObserver es la interfaz que define qué debe notificarse a cada uno de los subscriptores u observadores para indicarles que ha sucedido “algo” y que requiere de su atención. Más adelante veremos cómo funciona esto realmente, pero lo que tenemos que tener en cuenta es que contiene un método llamado UpdateState() que se encarga de actualizar ese estado o hecho.

ISubject es la interfaz que define las acciones que pueden acometerse con respecto a cada uno de sus observadores. Es decir, conoce a sus observadores y le permite subscribirse, desubscribirse, y notificar a todos y cada uno de sus subscriptores la notificación correspondiente (en nuestro caso, llamar a UpdateState()).

Subject es para esta primera aproximación una clase que implementa ISubject y que es consumida por la aplicación de ejemplo y demostración del funcionamiento y uso de este patrón. Como vemos, para esta primera aproximación he querido crear un proyecto que contenga esta clase también como clase que contenga esta funcionalidad y que muestre como generarla a partir de ISubject, algo que haremos en la segunda aproximación para mostrar las dos opciones generales.

El diagrama general de clases del proyecto es el que se indica a continuación:

El código de nuestras clases es el que se indica a continuación:

IObserver

namespace PatternObserver
{
 
    /// <summary>
    /// Interface del patrón Observer.
    /// </summary>
    public interface IObserver
    {
 
        /// <summary>
        /// Método encargado de indicar que el estado del proceso debe actualizarse para que 
        /// indique a los observadores "algo".
        /// </summary>
        /// <param name="sender">Indicamos la interfaz a quién se le envía la notificación.</param>
        void UpdateState(ISubject sender);
 
    } // IObserver
 
} // PatternObserver

 

ISubject

namespace PatternObserver
{
 
    /// <summary>
    /// Interface del patrón Observer.
    /// </summary>
    public interface ISubject
    {
 
        /// <summary>
        /// Método encargado de notificar a todos y cada uno de los observadores que ha 
        /// sucedido "algo".
        /// Esto se realiza recorriendo todos los observadores subscritos y ejecutando por 
        /// cada uno de ellos el método UpdateState() implementado de IObserver.
        /// </summary>
        void Notify();
 
        /// <summary>
        /// Método encargado de subscribir un observador para que reciba las notificaciones.
        /// </summary>
        /// <param name="observer">Interfaz IObserver que indica el observador.</param>
        void Subscribe(IObserver observer);
 
        /// <summary>
        /// Método encargado de desubscribir un observador para que no reciba más 
        /// notificaciones.
        /// </summary>
        /// <param name="observer">Interfaz IObserver que indica el observador.</param>
        void Unsubscribe(IObserver observer);
 
    } // ISubject
 
} // PatternObserver

 

Subject

namespace PatternObserver
{
 
    using System.Collections.Generic;
 
 
    /// <summary>
    /// Clase encargada de implementar la interfaz ISubject para permitir registrar un
    /// observador, eliminar el registro de un observador y notificarle que ha sucedido "algo".
    /// </summary>
    public class Subject : ISubject
    {
 
        #region CONSTRUCTORS
 
            /// <summary>
            /// Constructor de la clase.
            /// </summary>
            public Subject()
            {
                // Instanciamos la colección de observadores.
                this.Observers = new List<object>();
            } // Subject Constructor
 
        #endregion
 
 
        #region PROPERTIES
 
            /// <summary>
            /// Propiedad privada encargada de contener todos los subscriptores.
            /// </summary>
            private List<object> Observers { get; set; }
 
        #endregion
 
 
        #region METHODS
 
            /// <summary>
            /// Método encargado de notificar al subscriptor que ha sucedido un evento que 
            /// requiere su atención.
            /// </summary>
            public void Notify()
            {
                // Recorremos cada uno de los observadores para notificarles el evento.
                foreach (IObserver observer in this.Observers)
                {
                    // Indicamos a cada uno de los subscriptores la actualización del 
                    // estado (evento) producido.
                    observer.UpdateState(this);
                }
            } // Notify
        
 
            /// <summary>
            /// Método encargado de agregar un observador para que el subscriptor le 
            /// pueda notificar al subscriptor el evento.
            /// </summary>
            /// <param name="observer">Interfaz IObserver que indica el observador.</param>
            public void Subscribe(IObserver observer)
            {
                // Agregamos el subscriptor a la lista de subscriptores del publicador.
                this.Observers.Add(observer);
            } // Subscribe
        
 
            /// <summary>
            /// Método encargado de eliminar un observador para que el subscriptor no le 
            /// notifique ningún evento más al que era su subscriptor.
            /// </summary>
            /// <param name="observer">Interfaz IObserver que indica el observador.</param>
            public void Unsubscribe(IObserver observer)
            {
                // Eliminamos el subscriptor de la lista de subscriptores del publicador.
                this.Observers.Remove(observer);
            } // Unsubscribe
        
        #endregion
 
 
    } // Subject
 
} // PatternObserver

 

En este caso, he creado una clase (Subject) que implementa la interfaz ISubject y que tiene varias partes diferenciadoras.

En primer lugar he creado una propiedad (Observers) que contendrá una lista de todos y cada uno de los observadores. Lógicamente, habrá que crear la vía o forma de registrar y eliminar del registro a un observador determinado. Esto lo haremos de acuerdo a la implementación de los métodos de la interfaz.

Por lo tanto, en la implementación de la interfaz prepararemos los tres métodos de la misma. El método Subscribe se encarga de registrar o insertar en la lista de observadores a un observador concreto, mientras que el método Unsubscribe se encarga de eliminar de la lista de observadores al observador en cuestión.

Indudablemente, tendremos que trabajar en el método Notify de una manera particular, y es que dentro de este método tendremos la obligación de recorrer todos y cada uno de los observadores registrados y llamar al método UpdateState() que se encargará de realizar la acción concreta que tenga que hacer y que implementaremos y veremos más adelante.

PatternObserverProject

Sobre el proyecto de aplicación Windows de ejemplo (PatternObserverProject), este está formado por las siguientes clases:

-          MainForm

-          SampleObserver

La explicación de cada una de estas clases es la siguiente:

MainForm es la clase formulario con diferentes controles de usuario y las acciones generales que forman parte de la demostración de uso de este patrón.

SampleObserver es la clase que implementa la interfaz IObserver y determina qué acción o acciones realiza en realidad UpdateState().

El diagrama general de clases del proyecto es el que se indica a continuación:

Para esta primera aproximación, he preparado una interfaz de usuario similar a la que se indica en la siguiente imagen:

Este ejemplo tiene tres botones que se encargan cada uno de ellos de añadir un observador a la lista de observadores. Al hacer clic sobre uno de estos botones se deshabilitará su control Button y se habilitará el homónimo pero para eliminar el observador correspondiente.

Finalmente, el botón de lanzar el evento, es el encargado de simular que ocurre “algo” y que los observadores deberán darse cuenta de que han sido informados de que ha pasado algo que requiere su atención.

Como es un ejemplo de demostración, ese “algo” es un mensaje en pantalla que nos va a indicar que observador es. Si registramos los tres observadores y pulsamos el botón de lanzar el evento, aparecerán tres mensajes en pantalla, uno por cada observador.

El código de nuestras clases es el que se indica a continuación:

MainForm

namespace PatternObserverProject
{
 
    using System;
    using System.Windows.Forms;
 
 
    /// <summary>
    /// Clase formulario de ejemplo y demostración del patrón Observer.
    /// </summary>
    public partial class MainForm : Form
    {
 
        #region CONSTRUCTORS
 
            /// <summary>
            /// Clase principal del formulario.
            /// </summary>
            public MainForm()
            {
                InitializeComponent();
            } // MainForm
 
        #endregion
 
 
        #region EVENTS
 
            /// <summary>
            /// Evento MainForm_Load encargado de ejecutarse al cargar el formulario 
            /// Windows de prueba para el patrón Observer.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void MainForm_Load(object sender, EventArgs e)
            {
                // Instanciamos a PatternObserver.Subject.
                this.SubjectDemo = new PatternObserver.Subject();
            } // MainForm_Load
 
 
            /// <summary>
            /// Evento encargado de subscribirse al publicador.
            /// Este evento simula al primer subscriptor.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnAddFirst_Click(object sender, EventArgs e)
            {
                this.btnRemoveFirst.Enabled = this.btnAddFirst.Enabled;
                this.btnAddFirst.Enabled = !this.btnAddFirst.Enabled;
                // Inicializamos la clase Observer correspondiente.
                // Simulamos la subscripción a Observer.
                this.Observer1 = new SampleObserver("Observador 1");
                this.SubjectDemo.Subscribe(this.Observer1);
            } // btnAddFirst_Click
 
 
            /// <summary>
            /// Evento encargado de eliminar la subscripción al publicador.
            /// Este evento simula al primer subscriptor.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnRemoveFirst_Click(object sender, EventArgs e)
            {
                this.btnRemoveFirst.Enabled = this.btnAddFirst.Enabled;
                this.btnAddFirst.Enabled = !this.btnRemoveFirst.Enabled;
                // Simulamos la eliminación de la subscripción a Observer.
                this.SubjectDemo.Unsubscribe(this.Observer1);
            } // btnRemoveFirst_Click
 
 
            /// <summary>
            /// Evento encargado de subscribirse al publicador.
            /// Este evento simula al segundo subscriptor.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnAddSecond_Click(object sender, EventArgs e)
            {
                this.btnRemoveSecond.Enabled = this.btnAddSecond.Enabled;
                this.btnAddSecond.Enabled = !this.btnAddSecond.Enabled;
                // Inicializamos la clase Observer correspondiente.
                // Simulamos la subscripción a Observer.
                this.Observer2 = new SampleObserver("Observador 2");
                this.SubjectDemo.Subscribe(this.Observer2);
            } // btnAddSecond_Click
 
 
            /// <summary>
            /// Evento encargado de eliminar la subscripción al publicador.
            /// Este evento simula al segundo subscriptor.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnRemoveSecond_Click(object sender, EventArgs e)
            {
                this.btnRemoveSecond.Enabled = this.btnAddSecond.Enabled;
                this.btnAddSecond.Enabled = !this.btnRemoveSecond.Enabled;
                // Simulamos la eliminación de la subscripción a Observer.
                this.SubjectDemo.Unsubscribe(this.Observer2);
            } // btnRemoveSecond_Click
 
 
            /// <summary>
            /// Evento encargado de subscribirse al publicador.
            /// Este evento simula al tercer subscriptor.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnAddThird_Click(object sender, EventArgs e)
            {
                this.btnRemoveThird.Enabled = this.btnAddThird.Enabled;
                this.btnAddThird.Enabled = !this.btnAddThird.Enabled;
                // Inicializamos la clase Observer correspondiente.
                // Simulamos la subscripción a Observer.
                this.Observer3 = new SampleObserver("Observador 3");
                this.SubjectDemo.Subscribe(this.Observer3);
            } // btnAddThird_Click
 
 
            /// <summary>
            /// Evento encargado de eliminar la subscripción al publicador.
            /// Este evento simula al tercer subscriptor.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnRemoveThird_Click(object sender, EventArgs e)
            {
                this.btnRemoveThird.Enabled = this.btnAddThird.Enabled;
                this.btnAddThird.Enabled = !this.btnRemoveThird.Enabled;
                // Simulamos la eliminación de la subscripción a Observer.
                this.SubjectDemo.Unsubscribe(this.Observer3);
            } // btnRemoveThird_Click
 
 
            /// <summary>
            /// Evento encargado de simular una llamada al proceso que desencadena que los 
            /// subscriptores asociados al publicador reciban el evento de que se ha 
            /// desencadenado la acción.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnExecuteEvent_Click(object sender, EventArgs e)
            {
                // Lanzamos la notificación del proceso.
                this.SubjectDemo.Notify();
            } // btnExecuteEvent_Click
 
        #endregion
 
 
        #region PROPERTIES
 
            /// <summary>
            /// Propiedad encargada de instanciar a PatternObserver.Subject.
            /// </summary>
            private PatternObserver.Subject SubjectDemo { get; set; }
 
            /// <summary>
            /// Propiedad que utiliza la clase que implementa a Observer.
            /// </summary>
            private SampleObserver Observer1 { get; set; }
 
            /// <summary>
            /// Propiedad que utiliza la clase que implementa a Observer.
            /// </summary>
            private SampleObserver Observer2 { get; set; }
 
            /// <summary>
            /// Propiedad que utiliza la clase que implementa a Observer.
            /// </summary>
            private SampleObserver Observer3 { get; set; }
 
        #endregion
        
    } // MainForm
 
} // PatternObserverProject

 

SampleObserver

namespace PatternObserverProject
{
 
    /// <summary>
    /// Clase que implementa el patrón Observer.
    /// </summary>
    public class SampleObserver : PatternObserver.IObserver
    {
 
        #region CONSTRUCTORS
 
            /// <summary>
            /// Constructor de la clase.
            /// </summary>
            /// <param name="text">Parámetro utilizado para demostrar la implementación 
            /// correcta del patrón Observer.</param>
            public SampleObserver(string text)
            {
                // Indicamos el valor de la propiedad Text.
                this.Text = text;
            } // SampleObserver Constructor
 
        #endregion
 
 
        #region PROPERTIES
 
            /// <summary>
            /// Propiedad que es utilizada para saber qué instancia del subscriptor es lanzada
            /// en la notificación.
            /// </summary>
            private string Text { get; set; }
 
        #endregion
 
 
        #region IObserver Members
 
            /// <summary>
            /// Método utilizado para ser llamado desde el notificador ante un determinado 
            /// evento que ha sucedido en un momento dado y que requiere la atención por 
            /// todos y cada uno de los observadores o subscriptores.
            /// </summary>
            /// <param name="sender">Indicamos la interfaz a quién se le envía la notificación.</param>
            public void UpdateState(PatternObserver.ISubject sender)
            {
                System.Windows.Forms.MessageBox.Show(this.Text);
            } // UpdateState
 
        #endregion
 
    } // SampleObserver
 
} // PatternObserverProject

 

Esta última clase implementa la interfaz IObserver.

De esta manera, implementamos el método UpdateState(). Como podemos apreciar, este método llama a MessageBox.Show() para mostrar un mensaje en pantalla con el valor de la propiedad Text.

Como podemos apreciar es un ejemplo muy sencillo.

Si ejecutamos nuestra aplicación, veremos que ésta se comporta tal y como esperamos. Es decir, hacemos clic en los botones que queramos para agregar observadores a la lista de observadores, y posteriormente hacemos clic en el botón de lanzar evento.

Aproximación 2

La segunda aproximación es prácticamente banal una vez vista la aproximación anterior.

En la aproximación anterior hemos creado las interfaces y la clase Subject como implementación general para mostrar una forma particular y global del uso del patrón.

Si queremos implementar nuestra propia aproximación, quizás deberíamos tirar directamente de la interfaz.

PatternObserver

El diagrama general de lo que vamos a crear es lo que se puede observar en la siguiente imagen:

Esta imagen muestra claramente lo que comentaba anteriormente.

El proyecto de biblioteca de clases PatternObserver contiene únicamente las interfaces IObserver e ISubject.

El diagrama general de clases del proyecto es el que se indica a continuación:

El código y las explicaciones que daba anteriormente son las mismas.

PatternObserverProject

El proyecto de aplicación Windows (PatternObserverProject) en este caso, estará formado por las siguientes clases:

-          MainForm

-          SampleObserver

-          SampleSubject

La explicación de estas clases también la hemos comentado anteriormente.

La única cosa a tener en cuenta es que SampleSubject es una clase del proyecto de prueba que implementa a ISubject.

Para hacer este ejemplo un poco diferente, he modificado levemente esta clase. En lugar de utilizar un List<object> para registrar los observadores, he utilizado un ArrayList.

El diagrama general de clases del proyecto es el que se indica a continuación:

Para esta segunda aproximación, he incluido seis controles Button más a la interfaz de usuario tal y como se indica en la siguiente imagen:

Finalmente, incluiremos el código de nuestras clases:

MainForm

...
            /// <summary>
            /// Evento encargado de simular una llamada al proceso que desencadena que los 
            /// subscriptores asociados al publicador reciban el evento de que se ha 
            /// desencadenado la acción.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnExecuteEvent_Click(object sender, EventArgs e)
            {
                // Lanzamos la notificación del proceso.
                this.SubjectDemo.Notify();
                // Lanzamos la notificación del proceso.
                this.InternalSubjectDemo.Notify();
            } // btnExecuteEvent_Click
...
            /// <summary>
            /// Evento MainForm_Load encargado de ejecutarse al cargar el formulario 
            /// Windows de prueba para el patrón Observer.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void MainForm_Load(object sender, EventArgs e)
            {
                // Instanciamos a PatternObserver.Subject.
                this.SubjectDemo = new PatternObserver.Subject();
                // Instanciamos a SampleSubject que implementa la interfaz ISubject.
                this.InternalSubjectDemo = new SampleSubject();
            } // MainForm_Load
...
         /// <summary>
         /// Propiedad que utiliza la clase que implementa a Observer. 
         /// </summary>
         private SampleObserver ObserverInternal1 { get; set; }
      /// <summary>
      /// Propiedad que utiliza la clase que implementa a Observer. 
      /// </summary>
      private  SampleObserver ObserverInternal2 { get; set; }
            /// <summary>
            /// Propiedad encargada de instanciar la clase SampleSubject que implementa 
            /// PatternObserver.ISubject.
            /// </summary>
            private SampleSubject InternalSubjectDemo { get; set; }
...
            private void btnAddOne_Click(object sender, EventArgs e)
            {
                this.btnRemoveOne.Enabled = this.btnAddOne.Enabled;
                this.btnAddOne.Enabled = !this.btnAddOne.Enabled;
                // Inicializamos la clase Observer correspondiente.
                // Simulamos la subscripción a Observer.
                this.Observer1 = new SampleObserver("Observador 1 - Internal");
                this.InternalSubjectDemo.Subscribe(this.Observer1);
            }
 
            private void btnRemoveOne_Click(object sender, EventArgs e)
            {
                this.btnAddOne.Enabled = this.btnRemoveOne.Enabled;
                this.btnRemoveOne.Enabled = !this.btnRemoveOne.Enabled;
                // Simulamos la eliminación de la subscripción a Observer.
                this.InternalSubjectDemo.Unsubscribe(this.Observer1);
            }
 
            private void btnAddTwo_Click(object sender, EventArgs e)
            {
                this.btnRemoveTwo.Enabled = this.btnAddTwo.Enabled;
                this.btnAddTwo.Enabled = !this.btnAddTwo.Enabled;
                // Inicializamos la clase Observer correspondiente.
                // Simulamos la subscripción a Observer.
                this.Observer2 = new SampleObserver("Observador 2 - Internal");
                this.InternalSubjectDemo.Subscribe(this.Observer2);
            }
 
            private void btnRemoveTwo_Click(object sender, EventArgs e)
            {
                this.btnAddTwo.Enabled = this.btnRemoveTwo.Enabled;
                this.btnRemoveTwo.Enabled = !this.btnRemoveTwo.Enabled;
                // Simulamos la eliminación de la subscripción a Observer.
                this.InternalSubjectDemo.Unsubscribe(this.Observer2);
            }
...

 

Aquí únicamente indico aquellas partes que se crean y modifican en esta clase.

SampleSubject

namespace PatternObserverProject
{
 
    using System.Collections;
 
 
    /// <summary>
    /// Clase que implementa en este caso la clase ya preparada denominada Subject.
    /// Podríamos implementar ISubject y a partir de ella preparar todos sus métodos y 
    /// acciones, pero esta clase define como reutilizar una clase ya preparada para el
    /// propósito del patrón Observer.
    /// </summary>
    public class SampleSubject : PatternObserver.ISubject 
    {
 
        #region CONSTRUCTORS
 
            /// <summary>
            /// Constructor de la clase.
            /// </summary>
            public SampleSubject()
            {
                // Instanciamos la colección de observadores.
                this.Observers = new ArrayList();
            } // SampleSubject Constructor
 
        #endregion
 
 
        #region PROPERTIES
 
            /// <summary>
            /// Propiedad privada encargada de contener todos los subscriptores.
            /// </summary>
            private ArrayList Observers {get; set;}
 
        #endregion
 
 
        #region ISubject Members
 
            /// <summary>
            /// Método encargado de notificar al subscriptor que ha sucedido un evento que 
            /// requiere su atención.
            /// </summary>
            public void Notify()
            {
                // Recorremos cada uno de los observadores para notificarles el evento.
                foreach (PatternObserver.IObserver observer in this.Observers)
                {
                    // Indicamos a cada uno de los subscriptores la actualización del 
                    // estado (evento) producido.
                    observer.UpdateState(this);
                }
            } // Notify
 
 
            /// <summary>
            /// Método encargado de agregar un observador para que el subscriptor le 
            /// pueda notificar al subscriptor el evento.
            /// </summary>
            /// <param name="observer"></param>
            public void Subscribe(PatternObserver.IObserver observer)
            {
                // Agregamos el subscriptor a la lista de subscriptores del publicador.
                this.Observers.Add(observer);
            } // Subscribe
 
 
            /// <summary>
            /// Método encargado de eliminar un observador para que el subscriptor no le 
            /// notifique ningún evento más al que era su subscriptor.
            /// </summary>
            /// <param name="observer"></param>
            public void Unsubscribe(PatternObserver.IObserver observer)
            {
                // Eliminamos el subscriptor de la lista de subscriptores del publicador.
                this.Observers.Remove(observer);
            } // Unsubscribe
        
        #endregion
 
    } // SampleSubject
 
} // PatternObserverProject

 

En este caso, esta clase implementa la interfaz ISubject e implementa sus métodos correspondientes.

Conclusiones

En esta entrada hemos visto cómo implementar en .NET el patrón Observador (pattern Observer) y como funciona.

A partir de aquí, es cuestión de analizar si este patrón nos resulta útil e incluso la posibilidad de utilizar un patrón Observador modificado que satisfaga nuestras necesidades. Sin embargo, he creído interesante y útil hablar de este patrón que muchos desconocen u olvidan.

Descarga del proyecto en Visual Studio 2010 (PatternObserverProject.zip - 31 Kb).

 

Published 29/3/2011 18:00 por Jorge Serrano
Comparte este post:

Comentarios

Tuesday, March 29, 2011 6:53 PM por Jorge

# re: Patrón Observador en .NET - pattern Observer

Hola Jorge, gracias por el artículo, me ha paracido interesante. Lo única duda que me surge es con el tema de la aproximación 2. No me ha quedado muy claro el porque diferencias entre ambas ya que son practicamente igual, no??

Tuesday, March 29, 2011 6:59 PM por Jorge Serrano

# re: Patrón Observador en .NET - pattern Observer

Hola tocayo,

tienes razón cuando dices que son prácticamente iguales, y es que he querido jugar con dos formas de hacerlo diferentes.

La primera de ellas es creando una biblioteca de clases en la que tengamos las dos interfaces y una clase que implementa una de las interfaces.

La segunda está constituida por las mismas interfaces de la primera, pero sin la clase que implementa una de las interfaces, ya que esa implementación está en este segundo caso dentro del formulario Windows de ejemplo.

De esta manera, muestro dos formas de hacer lo mismo. Incluso en la primera de ellas se podría haber creado una clase dentro del proyecto Windows Forms que implementase la interfaz tal y como hago con la segunda aproximación, pero simplemente lo he hecho para tratar de dejarlo más claro y mostrar que la implementación no es vinculante al propio patrón ya que puede implementarse desde fuera de la misma biblioteca de clases.

Me ha venido muy bien tu pregunta para aclarar más esto, ya que sí creí que a lo mejor podría liar a la gente.

Si he liado un poco a alguien, pido perdón, pero espero que ahora quede aún mucho más claro. :)

Gracias por comentar.

Tuesday, March 29, 2011 7:46 PM por Juan Pablo

# re: Patrón Observador en .NET - pattern Observer

Me parece una buena explicacion del Patrón.

Pero, por poner alguna pega Jorge:

¿No seria posible que colgaras el proyecto para hacer las pruebas y revisarlo bien?.

Gracias.

Tuesday, March 29, 2011 8:47 PM por Jorge Serrano

# re: Patrón Observador en .NET - pattern Observer

Hola Juan Pablo.

Añadido. :)

Tuesday, March 29, 2011 9:22 PM por Juan Pablo

# re: Patrón Observador en .NET - pattern Observer

Joder Jorge.  Impresionante.

Ahora si que es un ariculo redondo. :)

Tuesday, March 29, 2011 9:58 PM por Marc Rubiño

# re: Patrón Observador en .NET - pattern Observer

Muy bueno Jorge, ahora te tienes que animar y seguir con la serie de patrones XD.

Saludos

Tuesday, March 29, 2011 10:03 PM por CarlosM

# re: Patrón Observador en .NET - pattern Observer

Me gusta muchisismo por que no tiene delegados ni eventos!!!!!

Tuesday, March 29, 2011 10:49 PM por Jorge Serrano

# re: Patrón Observador en .NET - pattern Observer

Muchas gracias a todos por vuestros comentarios.

Me alegro mucho de que os haya gustado (de eso se trata, de que guste y sobre todo de que resulte útil).

@Marc, voy a ver si me animo y sigo "patroneando" con más entradas de este tipo, aunque lleva un curro grandote, no te creas. :)

Un saludo.

Wednesday, March 30, 2011 7:33 AM por Javier Conesa

# re: Patrón Observador en .NET - pattern Observer

Jorge,

¿Que te parecería hacer un webcast sobre el tema de patrones en Second Nug?

Saludos!! ;-)

Wednesday, March 30, 2011 12:19 PM por Josué Yeray Julián Ferreiro

# re: Patrón Observador en .NET - pattern Observer

Yo secundo la moción de Javier... webcast de patrones yaaaa :D

Jorge, enhorabuena campeon, un artículo impecable :)

Wednesday, March 30, 2011 1:10 PM por Jorge Serrano

# re: Patrón Observador en .NET - pattern Observer

Gracias a ambos @Javier y @Yeray.

Ahora mismo por tiempo y demás, no me veo con ganas de hacer el webcast, pero dadme tiempo a que termine alguna entrada más que tengo en mente y luego cuando acabe lo veo. :)

Wednesday, March 30, 2011 1:10 PM por Juancar

# re: Patrón Observador en .NET - pattern Observer

Interesante artículo. ¿Recomiendas algún libro sobre patrones de diseño en C#?.

Wednesday, March 30, 2011 2:19 PM por Julio Alamo

# re: Patrón Observador en .NET - pattern Observer

@Juancar, te recomiendo este libro "Head First Design Patterns"

(www.amazon.com/.../ref=cm_li_v_cd_d)

Un saludo :)

Thursday, March 31, 2011 9:31 AM por Joaquín Sosa Martín

# re: Patrón Observador en .NET - pattern Observer

Muchas gracias Jorge, muy bien explicado. Ahora lo queremos online en Second Nug :P

Thursday, March 31, 2011 10:10 AM por Jorge Serrano

# re: Patrón Observador en .NET - pattern Observer

Gracias por aportar @Julio. :)

@Joaquín, ¡que presión!. :)))

A ver si termino las cosas que tengo entre manos y si acaso me aventuro para el evento. No lo descarto, simplemente digo no de momento por falta de tiempo y porque quiero escribir aún alguna entrada más. ;)

Saludos.

Thursday, March 31, 2011 11:39 AM por Jesus

# re: Patrón Observador en .NET - pattern Observer

Un gran aporte.

Muchar gracias, un articulo muy bien hecho y sencillo de entender.

SALUDOS

Friday, May 20, 2011 9:50 PM por Jorge Serrano

# re: Patrón Observador en .NET - pattern Observer

Muchas gracias Jesús. :)