¿Todavía recuerdas cómo cooperaron los gángsters en la película de policía y gángsters? Cuando una pandilla es robo, una o dos personas siempre toman el viento en la puerta. Si hay algún movimiento, los cómplices dentro serán notificados de inmediato para retirarse con urgencia. Quizás la persona que permite que las noticias no conozcan necesariamente cada cómplice en él; Y puede haber un nuevo hermano menor que no conoce al que deja las noticias. Pero esto no es nada, no puede afectar sus comunicaciones porque tienen un código acordado.
Jaja, la relación entre el Air Venter y el ladrón mencionado anteriormente es un ejemplo vivo del patrón del observador en la realidad.
El modo Observer también se conoce como modo de publicación/suscripción. GOF define el patrón del observador de la siguiente manera: define una dependencia de uno a muchos entre objetos. Cuando cambia el estado de un objeto, todos los objetos que dependen de él se notifican y se actualizan automáticamente.
Aquí hablaré primero sobre un principio importante del diseño orientado a objetos: el principio de responsabilidad única. Por lo tanto, cada objeto del sistema debe centrarse en abstracciones discretas en el dominio del problema. Por lo tanto, idealmente, un objeto solo hace una cosa. Esto trae muchos beneficios en el desarrollo: proporciona reutilización y mantenimiento, y también es una buena base para la refactorización.
Por lo tanto, casi todos los patrones de diseño se basan en este principio de diseño básico. Creo que el origen del modelo Observador debería estar en el procesamiento de la GUI y los datos comerciales, porque la mayoría de los ejemplos que explican el modelo Observer ahora son este tema. Sin embargo, la aplicación del modo Observador de ninguna manera se limita a este aspecto.
Bueno, la comprensión de la definición siempre requiere instancias para analizar. Las cuentas de servicio WeChat son bastante populares hoy en día. Vamos a presentarle el modelo Observer con el fondo de las cuentas de servicio WeChat.
Mira una imagen:
Cada usuario tiene 3 líneas en la imagen de arriba, que se omiten para dejar claro la imagen.
Como se muestra en la imagen de arriba, el número de servicio es nuestro tema y el usuario es el observador. Ahora aclaramos las siguientes funciones:
1. La cuenta de servicio es el tema, y el negocio está presionando mensajes
2. Los observadores solo necesitan suscribirse al tema, y se enviarán tan pronto como haya nuevas noticias.
3. Dan suscripción cuando no desee este mensaje de tema
4. Mientras la cuenta de servicio todavía esté allí, alguien se suscribirá. Ahora echemos un vistazo al diagrama de clases del patrón del observador:
El siguiente es la hora del código, simulamos una cuenta de servicio de lotería 3D WeChat y algunos suscriptores.
Primero, comience a escribir sobre nuestra interfaz de tema y la interfaz Observador:
paquete com.zhy.pattern.observer; / ** * Interfaz de tema, todos los temas deben implementar esta interfaz * * @author zhy * */ pública interfaz asunto {/ ** * registrar un observador * * @param observador */ public void registreBServer (observador observador); / ** * eliminar un observador * * @param observador */ public void removeBServer (observador observador); / *** notificar a todos los observadores*/ public void notifyObServers (); } paquete com.zhy.pattern.observer; / *** @author zhy Todos los observadores necesitan implementar esta interfaz*/ pública interfaz observador {public void Update (String msg); }Siguiente clase de implementación del número de servicio 3D:
paquete com.zhy.pattern.observer; import java.util.arrayList; import java.util.list; Public Class ObjectFor3D Implementa sujeto {Lista privada <Sobrerver> Observers = new ArrayList <Smanterver> (); / *** Número de lotería 3D*/ String privado Msg; @Override public void RegistroBServer (Observer Observer) {observadores.Add (observador); } @Override public void RemoLoBServer (Observer Observer) {int index = observvers.IndexOf (observador); if (index> = 0) {observadores.remove (index); }} @Override public void notifyObServers () {for (Observer Observer: Observers) {observador.Update (msg); }} / ** * Mensaje de actualización del tema * * @param msg * / public void setmsg (string msg) {this.msg = msg; notifyObServers (); }}Simular dos usuarios:
paquete com.zhy.pattern.observer; Public Class Observer1 implementa observador {asunto privado sujeto; Public ObserVer1 (sujeto sujeto) {this.subject = sujeto; sujeto. RegisterObServer (esto); } @Override public void Update (string msg) {system.out.println ("Observer1 obtiene el número 3D ->" + msg + ", quiero escribirlo"); }} paquete com.zhy.pattern.observer; Public Class Observer2 Implementa Observador {Asunto privado sujeto; Public ObserVer2 (sujeto sujeto) {this.subject = sujeto; sujeto. RegisterObServer (esto); } @Override public void Update (string msg) {system.out.println ("Observer2 obtiene el número 3D ->" + msg + "Quiero decirle a mis compañeros de cuarto"); }} Se puede ver que todos los usuarios que se suscriben a mensajes se mantienen en la cuenta de servicio, y todos los usuarios son notificados cuando hay un nuevo mensaje en la cuenta de servicio. Toda la arquitectura es un acoplamiento suelto, y la implementación del tema no depende del usuario. Cuando se agrega un nuevo usuario, el código del tema no necesita cambiarse; cómo el usuario procesa los datos obtenidos no tiene nada que ver con el tema;
Finalmente, mire el código de prueba:
paquete com.zhy.pattern.observer.test; import com.zhy.pattern.observer.objectfor3d; import com.zhy.pattern.observer.observer; import com.zhy.pattern.observer.observer1; import com.zhy.pattern.observer.observer2; import com.zhy.pattern.observer.subject; Prueba de clase pública {public static void main (string [] args) {// simula un número de servicio 3D ObjectFor3d SUMTAFFOR3D = new ObjectFor3d (); // Customer1 Observer Observer1 = New Observer1 (Sujeto para 3D); Observador observador2 = new Observer2 (sujeto 3D); Sujeto3D.SetMsg ("El número 3D 20140420 es: 127"); Sujeto3D.SetMsg ("El número 3D 20140421 es: 333"); }}Resultado de salida:
Observer1 obtiene el número 3D -> El número 3D 20140420 es: 127, quiero escribirlo. Observer2 obtiene el número 3D -> El número 3D 20140420 es: 127 Quiero contarle a mis compañeros de cuarto. Observer1 obtiene el número 3D -> 20140421 El número 3D es: 333, quiero escribirlo. Observer2 obtiene el número 3D -> 20140421 El número 3D es: 333 Quiero contarle a mis compañeros de cuarto.
Hay muchos lugares en JDK o Andorid que implementan el modo Observador, como xxxview.addxxxlistenter. Por supuesto, xxxview.setonxxxListener no es necesariamente un modo observador, porque el modo observador es una relación de uno a muchos. Para SetXXXListener, es una relación de 1 a 1, y debe llamarse una devolución de llamada.
Felicitaciones por aprender el modo observador. El modo observador anterior nos permite escribirlo desde cero. Por supuesto, Java nos ha ayudado a implementar el modo observador, con la ayuda de java.util.observable y java.util.observer.
A continuación usamos clases incorporadas Java para implementar el patrón Observador:
En primer lugar, hay un tema de número de servicio de lotería 3D:
paquete com.zhy.pattern.observer.java; import java.util.observable; public class Sujetfor3d extiende observable {string privado msg; public String getMsg () {return msg; } / ** * Mensaje de actualización del tema * * @param msg * / public void setmsg (string msg) {this.msg = msg; setchanged (); notifyObServers (); }}El siguiente es el tema de un número de servicio de bola de doble color:
paquete com.zhy.pattern.observer.java; import java.util.observable; public class SujetForsSq extiende observable {String privado Msg; public String getMsg () {return msg; } / ** * Mensaje de actualización del tema * * @param msg * / public void setmsg (string msg) {this.msg = msg; setchanged (); notifyObServers (); }}Finalmente, nuestros usuarios:
paquete com.zhy.pattern.observer.java; import java.util.observable; import java.util.observer; Public Class Observer1 implementa Observer {public void RegisterSubject (observable observable) {observable.AdDobServer (this); } @Override public void Update (observable o, objeto arg) {if (o instanciaf sometfor3d) {SUMTORFOR3D SUMTAFOR3D = (SUMTORFOR3D) O; System.out.println ("SUTMAFFOR3D MSG ->" + SUMTOR3D.GETMSG ()); } if (o instanciaf sometforssq) {sometforssq sometforssq = (sometforssq) o; System.out.println ("SUSPELFORSSQ'S MSG ->" + SUSPUSTFORSSQ.GETMSG ()); }}}Mira un código de prueba:
paquete com.zhy.pattern.observer.java; Prueba de clase pública {public static void main (string [] args) {SUMTFOR3D SUMTAFOR3D = new SujetoFor3D (); SUSTFORSSQ SUSPUSTFORSSQ = new SujetForsSq (); Observador1 observador1 = new Observer1 (); Observer1.RegisterSubject (sujeto 3D); Observer1.RegisterSubject (SujetForsSq); Sujeto3d.SetMsg ("Hola 3d'nums: 110"); SUMPLETFORSSQ.SETMSG ("SSQ'NUMS: 12,13,31,5,4,3 15"); }}Resultados de la prueba:
Mensaje de sujeto3d -> Hola 3d'nums: 110 Mensaje de Sujeto Sujeto -> SSQ'Nums: 12,13,31,5,4,3 15 15
Se puede ver que el uso de clases incorporadas de Java para implementar el patrón Observer, el código es muy conciso. Por cierto, AddObServer, RemoLoBServer, notifyObServers se han implementado para nosotros. Todo lo que podemos ver que observable es una clase, no una interfaz. Básicamente, el libro tiene una actitud negativa hacia el diseño de Java. Se siente que el patrón de observador incorporado de Java viola el principio de la programación orientada a la interfaz. Sin embargo, si lo piensa, está escribiendo el patrón de observador aquí (nuestra propia implementación). La idea de la interfaz es muy buena, pero si continúa agregando muchos temas ahora, el DDOBSERVER, RemoLoBServer, NotifyObServers para cada tema son básicamente los mismos. Las interfaces no pueden implementar la reutilización del código, y no hay forma de usar el modo combinado para lograr la reutilización de estos tres métodos, por lo que creo que es razonable implementar estos tres métodos en la clase aquí.