Consideremos primero el siguiente escenario para comprender el patrón del observador.
Escenario :
Supongamos que estamos creando una aplicación de cricket que notifica a los espectadores sobre la información, como el puntaje actual, la tasa de ejecución, etc. Supongamos que hemos creado dos elementos de visualización CurrentScoreDisplay y AverageScoreDisplay. CricketData tiene todos los datos (carreras, bolos, etc.) y cada vez que los datos cambian, los elementos de la pantalla reciben una notificación con nuevos datos y muestran los datos más recientes en consecuencia.
A continuación se muestra la implementación de Java de este diseño.
// Java implementation of above design for Cricket App. The // problems with this design are discussed below. // A class that gets information from stadium and notifies // display elements, CurrentScoreDisplay & AverageScoreDisplay class CricketData { int runs, wickets; float overs; CurrentScoreDisplay currentScoreDisplay; AverageScoreDisplay averageScoreDisplay; // Constructor public CricketData(CurrentScoreDisplay currentScoreDisplay, AverageScoreDisplay averageScoreDisplay) { this.currentScoreDisplay = currentScoreDisplay; this.averageScoreDisplay = averageScoreDisplay; } // Get latest runs from stadium private int getLatestRuns() { // return 90 for simplicity return 90; } // Get latest wickets from stadium private int getLatestWickets() { // return 2 for simplicity return 2; } // Get latest overs from stadium private float getLatestOvers() { // return 10.2 for simplicity return (float)10.2; } // This method is used update displays when data changes public void dataChanged() { // get latest data runs = getLatestRuns(); wickets = getLatestWickets(); overs = getLatestOvers(); currentScoreDisplay.update(runs,wickets,overs); averageScoreDisplay.update(runs,wickets,overs); } } // A class to display average score. Data of this class is // updated by CricketData class AverageScoreDisplay { private float runRate; private int predictedScore; public void update(int runs, int wickets, float overs) { this.runRate = (float)runs/overs; this.predictedScore = (int) (this.runRate * 50); display(); } public void display() { System.out.println("\nAverage Score Display:\n" + "Run Rate: " + runRate + "\nPredictedScore: " + predictedScore); } } // A class to display score. Data of this class is // updated by CricketData class CurrentScoreDisplay { private int runs, wickets; private float overs; public void update(int runs,int wickets,float overs) { this.runs = runs; this.wickets = wickets; this.overs = overs; display(); } public void display() { System.out.println("\nCurrent Score Display: \n" + "Runs: " + runs +"\nWickets:" + wickets + "\nOvers: " + overs ); } } // Driver class class Main { public static void main(String args[]) { // Create objects for testing AverageScoreDisplay averageScoreDisplay = new AverageScoreDisplay(); CurrentScoreDisplay currentScoreDisplay = new CurrentScoreDisplay(); // Pass the displays to Cricket data CricketData cricketData = new CricketData(currentScoreDisplay, averageScoreDisplay); // In real app you would have some logic to call this // function when data changes cricketData.dataChanged(); } }
Producción:
Current Score Display: Runs: 90 Wickets:2 Overs: 10.2 Average Score Display: Run Rate: 8.823529 PredictedScore: 441
Problemas con el diseño anterior :
- CricketData contiene referencias a objetos de elementos de visualización concretos, aunque solo necesita llamar al método de actualización de estos objetos. Tiene acceso a demasiada información adicional de la que requiere.
- Esta declaración “currentScoreDisplay.update(runs,wickets,overs);” viola uno de los principios de diseño más importantes «Programa para interfaces, no implementaciones». ya que estamos usando objetos concretos para compartir datos en lugar de interfaces abstractas.
- CricketData y los elementos de visualización están estrechamente relacionados.
- Si en el futuro surge otro requisito y necesitamos agregar otro elemento de visualización, debemos realizar cambios en la parte no variable de nuestro código (CricketData). Definitivamente, esta no es una buena práctica de diseño y es posible que la aplicación no pueda manejar los cambios y no sea fácil de mantener.
¿Cómo evitar estos problemas?
Usar patrón de observador
Patrón de observador
Para comprender el patrón del observador, primero debe comprender el sujeto y los objetos del observador.
La relación entre sujeto y observador puede entenderse fácilmente como una analogía con la suscripción a una revista.
- Un editor de revistas (sujeto) está en el negocio y publica revistas (datos).
- Si usted (usuario de datos/observador) está interesado en la revista, se suscribe (registra), y si se publica una nueva edición, se la envían.
- Si se da de baja (darse de baja) dejará de recibir nuevas ediciones.
- Publisher no sabe quién es usted y cómo usa la revista, simplemente se la entrega porque usted es un suscriptor (acoplamiento suelto).
Definición:
El patrón de observador define una dependencia de uno a muchos entre objetos, de modo que un objeto cambia de estado, todos sus dependientes son notificados y actualizados automáticamente.
Explicación:
- La dependencia de uno a muchos es entre Sujeto (Uno) y Observador (Muchos).
- Hay dependencia ya que los propios observadores no tienen acceso a los datos. Dependen del Sujeto para que les proporcione datos.
Diagrama de clase:
Fuente de la imagen: Wikipedia
- Aquí, Observer y Subject son interfaces (pueden ser cualquier supertipo abstracto, no necesariamente una interfaz Java).
- Todos los observadores que necesitan los datos deben implementar la interfaz de observador.
- El método de notificación() en la interfaz del observador define la acción que se tomará cuando el sujeto proporcione sus datos.
- El sujeto mantiene una colección de observadores que es simplemente la lista de observadores actualmente registrados (suscritos).
- registerObserver(observer) y unregisterObserver(observer) son métodos para agregar y eliminar observadores respectivamente.
- se llama a applyObservers() cuando se modifican los datos y es necesario proporcionar nuevos datos a los observadores.
Ventajas:
proporciona un diseño débilmente acoplado entre objetos que interactúan. Los objetos débilmente acoplados son flexibles con los requisitos cambiantes. Aquí el acoplamiento débil significa que los objetos que interactúan deberían tener menos información entre sí.
El patrón del observador proporciona este acoplamiento flojo como:
- El sujeto solo sabe que el observador implementa la interfaz del observador. Nada más.
- No es necesario modificar Asunto para agregar o eliminar observadores.
- Podemos reutilizar las clases sujeto y observador independientemente una de la otra.
Desventajas:
- Pérdidas de memoria causadas por el problema del oyente caducado debido al registro explícito y la cancelación del registro de los observadores.
¿Cuándo usar este patrón?
Debería considerar usar este patrón en su aplicación cuando varios objetos dependen del estado de un objeto, ya que proporciona un diseño limpio y bien probado para el mismo.
Usos en la vida real:
- Se usa mucho en los kits de herramientas de GUI y en el detector de eventos. En java, el botón (sujeto) y onClickListener (observador) se modelan con un patrón de observador.
- Redes sociales, feeds RSS, suscripción por correo electrónico en el que tiene la opción de seguir o suscribirse y recibe la última notificación.
- Todos los usuarios de una aplicación en Play Store reciben una notificación si hay una actualización.
Patrón de observador | Conjunto 2 (Implementación)
Lectura adicional: método del observador en Python
Este artículo es una contribución de Sulabh Kumar . Si le gusta GeeksforGeeks y le gustaría contribuir, también puede escribir un artículo y enviarlo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.
Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.
Publicación traducida automáticamente
Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA