Patrón Observer: ¿en qué consiste este patrón de diseño?

No son pocos los aspectos que hay que tener en cuenta al programar software: el producto final, por ejemplo, no solo ha de disponer de las funciones deseadas, sino que su código fuente también ha de ser legible y comprensible. Naturalmente, para conseguirlo, ha de invertirse el menor esfuerzo posible, especialmente si se desarrollan programas o partes de ellos con funciones o elementos recurrentes. Los llamados patrones GoF (Gang of Four) ofrecen para esta finalidad una gama de soluciones predefinidas a diversos problemas típicos del diseño de software.

Al igual que otros patrones populares como el patrón Visitor y el patrón Singleton, el llamado patrón Observer también forma parte de esta colección de prácticos patrones de diseño que tanto facilitan el día a día de los programadores. Te contamos en qué consiste el patrón Observer (incluyendo una representación gráfica en UML) y qué ventajas y desventajas presenta.

¿Qué es el patrón Observer?

El patrón de diseño Observer, Observer Pattern o patrón observador es uno de los patrones de diseño de software más populares. Esta herramienta ofrece la posibilidad de definir una dependencia uno a uno entre dos o más objetos para transmitir todos los cambios de un objeto concreto de la forma más sencilla y rápida posible. Para conseguirlo, puede registrarse en un objeto (observado) cualquier otro objeto, que funcionará como observador. El primer objeto, también llamado sujeto, informa a los observadores registrados cada vez que es modificado.

Como ya hemos mencionado, el patrón Observer es uno de los patrones GoF incluidos en el libro de 1994 Design Patterns: Elements of Reusable Object-Oriented Software. Las más de 20 soluciones de diseño descritas en esta publicación siguen teniendo un papel importante hoy en día en la conceptualización y el desarrollo de aplicaciones informáticas.

Finalidad y funcionamiento del patrón Observer

El patrón Observer trabaja con dos tipos de actores: por un lado, el sujeto, es decir, el objeto cuyo estado quiere vigilarse a largo plazo. Por otro lado, están los objetos observadores, que han de ser informados de cualquier cambio en el sujeto.

Hecho

Por lo general, un sujeto tiene asignados varios observadores, pero, en principio, el patrón Observer también puede aplicarse con un único objeto observador.

Sin el patrón Observer, los objetos observadores tendrían que solicitar al sujeto regularmente que les enviase actualizaciones acerca de su estado (status updates). Cada una de estas solicitudes conllevaría tiempo de computación y requeriría, además, ciertos recursos de hardware. El patrón Observer se basa en la idea de centralizar la tarea de informar en manos del sujeto. Para conseguirlo, existe una lista en la que los observadores pueden registrarse. En caso de modificación, el sujeto los informa uno tras otro, sin necesidad de que los observadores lo pidan activamente. Si, más adelante, un observador ya no necesita las actualizaciones automáticas, puede simplemente retirarse de la lista.

Nota

Para informar a cada uno de los observadores pueden aplicarse dos métodos diferentes. Con el método push, el sujeto indica directamente en su mensaje qué cambios se han producido. Este método puede causar problemas si se transmiten informaciones que el observador no es capaz de procesar. El método pull, en cambio, no presenta este problema: con él, el sujeto tan solo transmite la información de que se han producido cambios. Si los observadores quieren saber de qué cambios se trata, han de solicitar el estado actualizado mediante una llamada a método especial.

Representación gráfica del patrón Observer (diagrama UML)

El modo de funcionamiento y uso de los patrones de diseño, como el patrón Observer, suele ser difícil de entender para quienes no están familiarizados con el tema. Para facilitar la comprensión, puede ser útil observar una representación gráfica del patrón de diseño. El extendido lenguaje de modelamiento UML (Unified Modeling Language) se adecúa especialmente a este propósito, ya que permite describir las relaciones de forma comprensible e intuitiva, tanto para los usuarios de la aplicación, como para los expertos. Por eso, hemos escogido UML como lenguaje de modelación para ofrecer la siguiente representación abstracta del patrón Observer.

¿Qué ventajas e inconvenientes presenta el patrón Observer?

El patrón Observer puede ser la solución adecuada a numerosos problemas de diseño. Su mayor ventaja es el alto grado de independencia entre el objeto observado (sujeto) y los objetos observadores interesados en el estado actual del sujeto. El objeto observado no requiere ningún tipo de información acerca de los observadores, puesto que la interacción se realiza de manera independiente a través de la interfaz de los observadores, que reciben actualizaciones automáticamente. De esta manera, ya no se realizan solicitudes en vano (cuando el sujeto no se ha modificado desde la última solicitud).

Sin embargo, las actualizaciones automáticas por parte del sujeto hacia todos los observadores registrados no siempre es una ventaja, ya que las informaciones de cambios transmitidas pueden ser irrelevantes para ciertos observadores. Este proceso supone un inconveniente especialmente cuando el número de observadores registrados es muy alto, puesto que se malgasta mucho tiempo de computación. Otra desventaja del patrón Observer es que el código fuente del sujeto a menudo no revela qué observadores están siendo informados.

¿Dónde se aplica el patrón observador?

El patrón de diseño Observer se implementa sobre todo en aplicaciones basadas en componentes cuyo estado,

  • por un lado, es muy observado por otros componentes
  • y, por otro, es modificado regularmente.

Algunos de los casos de aplicación típicos de este patrón son las GUI (interfaces gráficas de usuario), que actúan como interfaz de comunicación de manejo sencillo entre los usuarios y el programa. Cada vez que se modifican los datos, estos deben actualizarse en todos los componentes de la GUI. Esta situación es perfecta para la aplicación de la estructura sujeto-observador del patrón Observer. Incluso los programas que trabajan con conjuntos de datos en formato visual (ya sean tablas clásicas o diagramas gráficos) pueden beneficiarse de la estructura de este patrón de diseño.

En lo que respecta al lenguaje de programación, el patrón Observer no conlleva, en principio, ninguna limitación específica. El único requisito es que el paradigma orientado a objetos sea compatible con el patrón. Algunos de los lenguajes más utilizados para implementar el patrón Observer son C#, C++, Java, JavaScript, Python y PHP.

Patrón Observer: ejemplo de aplicación

Puede llegar a haber grandes diferencias en el modo de implementación del patrón Observer según el lenguaje de programación utilizado. Sin embargo, el concepto básico de la implementación es siempre el mismo: el acceso a un objeto concreto (o a su estado) se pone a disposición de muchos otros objetos. El tutorial del patrón Observer de javabeginners.de ofrece un ejemplo muy representativo de lo que ocurre en la práctica y que puede ser muy útil para comprender este concepto.

En el ejemplo se quiere mostrar un texto publicado por el emisor en los campos de texto de varios receptores. Para ello, la subjectclass (emisor, sujeto) añade a la observableclass el método addObserver(). De este modo, pueden añadirse receptores. Además, se introduce el método setChanged(), que registra cambios en el sujeto y hace una llamada a notifyObservers() en caso de cambios, para informar así a todos los observadores.

class emisor extends Observable {
	public emisor(){
		this.addObserver(new receptores_1());
		this.addObserver(new receptores_2());
		tell("Text");
	}
	public void tell(String info){
		if(countObservers()>0){
			setChanged();
			notifyObservers(info);
		}
	}
}

Los observadores necesitan, además, una implementación de la interfaz de observación, incluyendo el método udpate() y dos argumentos: el objeto observado y el cambio en forma de instancia de objeto (ConcreteSubject).

class receptores extends JFrame implements Observer{
	private JTextField field;
	public receptores (){
		field1 = new JTextField("a");
		add(field);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setSize(300, 50);
		setVisible(true);
	}
	public void update(Observable o, Object arg) {
		field.setText((String) arg);
	}
}
¿Le ha resultado útil este artículo?
Page top