Implementación de patrón de observador simple
Copie el código de código de la siguiente manera:
importar java.util.ArrayList;
importar java.util.Collections;
importar java.util.Iterator;
importar java.util.List;
/**
* Las devoluciones de llamada se utilizan en el modo observador:
* A. El observador se registra en la lista de oyentes de los observados y la propia clase de observador proporciona una función de devolución de llamada.
* B. El Observable (Observable o Sujeto) mantiene una lista de observadores y puede registrar y dar de baja observadores
* C. Una vez que cambia el estado del observador, puede llamar a notifyObservers(). Este método recorrerá la lista de observadores y los llamará uno por uno.
función de devolución de llamada proporcionada por el observador
* @autor lo hará
*
*/
clase pública SimpleObserverPattern {
público estático vacío principal (String [] argumentos) {
SimpleObserverPattern sop = nuevo SimpleObserverPattern();
Lista<IObserver> observadores = new ArrayList<IObserver> ();
IObserver observadorA = sop.new Observador("ObservadorA");
IObserver observadorB = sop.new Observador("ObservadorB");
observadores.add(observadorA);
observadores.add(observadorB);
IObservable observable = sop.new Observable(observadores);
observable.registerObserver(sop.new Observer("ObserverC"));
observable.changeState();
observable.close();
}
// La persona observada se llama Sujeto en algunos lugares.
interfaz IObservable {
registro nuloObserver(observador IObserver);
anular unregisterObserver (observador IObserver);
anular notificarObservadores();
Cadena getState();
estado de cambio nulo();
cierre vacío();
}
clase Observable implementa IObservable {
cadena final estática privada NUEVO = "Nuevo";
cadena final estática privada CAMBIADO = "Cambiado";
cadena final estática privada CERRADO = "Cerrado";
estado de cadena privada;
observadores privados de Lista<IObserver>;
observable público() {
esto (nulo);
}
Observable público (Lista de observadores <IObserver>) {
si (observadores == nulo) {
observadores = new ArrayList<IObserver> ();
}
this.observers = Collections.synchronizedList(observadores);
this.state = NUEVO;
}
@Anular
registro público vacíoObserver (observador IObserver) {
observadores.add(observador);
}
@Anular
public void unregisterObserver (observador IObserver) {
observadores.remove(observador);
}
@Anular
notifyObservers públicos vacíos() {
Iterador<IObserver> iter = observadores.iterador();
mientras(iter.hasNext()) {
iter.next().actualizar(esto);
}
}
@Anular
cadena pública getState() {
estado de retorno;
}
@Anular
estado de cambio público vacío() {
this.state = CAMBIADO;
notificarObservadores();
}
@Anular
cierre público vacío() {
this.state = CERRADO;
notificarObservadores();
}
}
interfaz IObserver {
actualización nula (IObservable observalbe);
}
clase Observador implementa IObserver {
nombre de cadena privada;
Observador público (nombre de cadena) {
this.nombre = nombre;
}
@Anular
actualización de vacío público (IObservable observalbe) {
System.out.println(
String.format("%s recibe el cambio de observalbe, el estado actual de observalbe es %s",
nombre, observalbe.getState()));
}
}
}
La implementación anterior utiliza directamente el objeto observado como parámetro de función de devolución de llamada. Esto es muy poco elegante y puede funcionar en escenarios simples.
Pero, de hecho, en la mayoría de los casos, una persona observada tiene muchos eventos o estados, y cada observador puede estar interesado en diferentes eventos o estados, o con el fin de ocultar información, no queremos que todos los observadores puedan acceder a todos los estados. dentro del Observable.
De esta manera, continué evolucionando el código a la siguiente versión. Tenga en cuenta que aquí no consideré los problemas de concurrencia en detalle.
Copie el código de código de la siguiente manera:
importar java.util.Collections;
importar java.util.HashSet;
importar java.util.Hashtable;
importar java.util.Iterator;
importar java.util.Set;
clase pública MultiEventObserverPattern {
público estático vacío principal (String [] argumentos) {
MultiEventObserverPattern meop = nuevo MultiEventObserverPattern();
IObservable observable = meop.new Observable();
IObserver observadorA = meop.new Observador("ObservadorA");
IObserver observadorB = meop.new Observador("ObservadorB");
//Registrar eventos de interés
observable.registerObserver(observable.getEventA(), observadorA);
observable.registerObserver(observable.getEventB(), observadorB);
//Cambiar el estado observado
observable.changeStateA();
observable.changeStateB();
}
interfaz IEvent {
cambio de evento nulo();
Cadena getState();
}
clase EventA implementa IEvent {
cadena final estática privada INITIALIZED = "Inicializado";
Cadena final estática privada PENDIENTE = "Pendiente";
estado de cadena privada;
Evento públicoA() {
this.state = INICIALIZADO;
}
@Anular
cambio de evento público vacío () {
System.out.println("Cambio de eventoA");
this.state = PENDIENTE;
}
@Anular
cadena pública toString() {
devolver "EventoA";
}
@Anular
cadena pública getState() {
estado de retorno;
}
}
clase EventB implementa IEvent {
cadena final estática privada NUEVO = "Nuevo";
Cadena final estática privada IDLE = "Inactivo";
estado de cadena privada;
Evento públicoB() {
this.state = NUEVO;
}
@Anular
cambio de evento público vacío () {
System.out.println("Cambio de EventoB");
este.estado = INACTIVO;
}
@Anular
cadena pública toString() {
devolver "EventoB";
}
@Anular
cadena pública getState() {
estado de retorno;
}
}
// Observable, a veces llamado Asunto
interfaz IObservable {
void RegisterObserver (evento IEvent, observador IObserver);
void unregisterObserver (evento IEvent, observador IObserver);
//Notificar a los observadores que ha ocurrido un evento
anular notificarObservers (evento IEvent);
void cambioEstadoA();
anular cambioEstadoB();
IEvent getEventA();
IEvent getEventB();
}
clase Observable implementa IObservable {
evento privado IEventA;
evento privado IEventB;
Hashtable privado<IEvent, Set<IObserver>> eventObserverMapping;
observable público() {
esto (nulo);
}
// Si algunos de los Set<IObserver> pasados por evenObserverMapping no se han modificado sincrónicamente, no hay nada que puedas hacer al respecto.
público Observable (Hashtable<IEvent, Set<IObserver>> eventObserverMapping) {
if(eventObserverMapping == nulo) {
eventObserverMapping = new Hashtable<IEvent, Set<IObserver>> ();
}
this.eventObserverMapping = new Hashtable<IEvent, Set<IObserver>> ();
this.eventA = nuevo EventoA();
this.eventB = nuevo EventB();
}
@Anular
registro público vacíoObserver (evento IEvent, observador IObserver) {
Set<IObserver> observadores = eventObserverMapping.get(event);
si (observadores == nulo) {
observadores = Collections.synchronizedSet(new HashSet<IObserver> ());
observadores.add(observador);
eventObserverMapping.put(evento, observadores);
}
demás {
observadores.add(observador);
}
}
@Anular
public void unregisterObserver (evento IEvent, observador IObserver) {
Set<IObserver> observadores = eventObserverMapping.get(event);
si (observadores! = nulo) {
observadores.remove(observador);
}
}
@Anular
notifyObservers público vacío (evento IEvent) {
Set<IObserver> observadores = eventObserverMapping.get(event);
if(observadores!= nulo && observadores.tamaño() > 0) {
Iterador<IObserver> iter = observadores.iterador();
mientras(iter.hasNext()) {
iter.next().update(evento);
}
}
}
@Anular
cambio de estado vacío público () {
// Cambiar el estado A activará el evento A
eventoA.eventChange();
notificarObservadores(eventoA);
}
@Anular
cambio de estado público vacíoB() {
// Cambiar el estado B activará el evento B
eventoB.eventChange();
notificarObservadores(eventoB);
}
@Anular
IEvent público getEventA() {
evento de retornoA;
}
@Anular
IEvent público getEventB() {
evento de retorno B;
}
}
interfaz IObserver {
actualización nula (evento IEvent);
}
clase Observador implementa IObserver {
nombre de cadena privada;
Observador público (nombre de cadena) {
this.nombre = nombre;
}
@Anular
actualización de anulación pública (evento IEvent) {
System.out.println(
String.format("%s recibe el cambio de %s, el estado actual del observalbe es %s",
nombre, evento, evento.getState()));
}
}
}
Parece perfecto, pero aún no lo es. Porque los eventos están codificados como propiedades de la clase Observer. De esta manera, el tipo de evento se determina en el momento de la compilación. Si desea agregar un nuevo tipo de evento, debe modificar la interfaz IObservable y la clase Observable, lo que reduce en gran medida la flexibilidad.
Es equivalente a que el observador esté acoplado a estos eventos específicos, entonces, ¿cómo rompemos esta limitación?
La respuesta es introducir un nuevo componente y dejar que ese componente administre la relación entre eventos, observadores y objetos observados. Cuando ocurre un evento, ese componente también llamará a la función de devolución de llamada del observador. Esto también es una especie de desacoplamiento, algo similar al contenedor IOC de Spring.
En cuanto a la implementación específica, creo que Guava EventBus ha hecho un trabajo bastante bueno. Puede consultar el enlace que mencioné anteriormente.
PD: Esta publicación no es un anuncio de Guava EventBus, pero mis propias ideas se están avanzando paso a paso y gradualmente son consistentes con las ideas de diseño de Guava EventBus.
Continúemos mirando el ejemplo de la clase estándar JDK que implementa el patrón de observador y luego analicemos su implementación del código fuente. Todo lo que necesitamos ver es una clase Observable y una interfaz de Observador.
Las clases estándar JDK implementan el patrón de observador
Copie el código de código de la siguiente manera:
importar java.util.Observable;
importar java.util.Observer;
/**
* Implementar el patrón de observador usando clases estándar en el paquete java.util
* @autor lo hará
*
*/
clase pública JDKObserverDemo {
público estático vacío principal (String [] argumentos) {
JDKObserverDemo jod = nuevo JDKObserverDemo();
// observador
MiObservable miObservable = jod.new MiObservable("hola");
// observador
Observador miObservador = jod.new MiObservador();
// registro
miObservable.addObserver(miObservador);
// Cambia el estado observado y activa la función de devolución de llamada del observador.
myObservable.setValue("voluntad");
}
clase MyObservable extiende Observable {
cadena privada valor observado; // el valor observado
público MiObservable (Cadena valor observado) {
this.watchedValue = watchedValue;
}
setValue público vacío (String nuevoValue) {
if(!watchedValue.equals(nuevoValor)) {
valor observado = nuevo valor;
setCambiado();
notificarObservadores(nuevoValor);
}
}
@Anular
cadena pública toString() {
devolver "MiObservable";
}
}
clase MyObserver implementa Observador {
@Anular
actualización pública vacía (Observable o, Objeto arg) {
System.out.println(o + "el estado cambió, el argumento es: " + arg);
}
}
}
Después de observar la implementación de Observer y Observable en la biblioteca estándar JDK, es muy simple, así que no quiero decir más.
A continuación se muestra la implementación del oyente en Quartz.
Oyente QuartzScheduler
Copie el código de código de la siguiente manera:
importar java.util.ArrayList;
importar java.util.Fecha;
importar java.util.List;
/**
* Clase de núcleo de cuarzo, equivalente a Observable (observable)
* @autor lo hará
*
*/
clase pública QuartzScheduler {
privado ArrayList<SchedulerListener> internalSchedulerListeners = new ArrayList<SchedulerListener>(10);
//private ArrayList<JobListener> interanlJobListeners = new ArrayList<JobListener>() // Un Observable puede contener múltiples conjuntos de oyentes;
Fecha pública ScheduleJob (activador de activación) {
si (disparador == nulo) {
devolver nulo;
}
System.out.println("Programar trabajo, activador: " + activador);
notifySchedulerListenersScheduled(disparador);
devolver nueva fecha();
}
public void unScheduleJob (activador de activación) {
si (disparador == nulo) {
devolver;
}
System.out.println("Trabajo no programado, activador: " + activador);
notificarShedulerListenerUnScheduled(activador);
}
//Registrar SchedulerListener
public void addInternalSchedulerListener (SchedulerListener planificadorListener) {
sincronizado (internalSchedulerListeners) {
internalSchedulerListeners.add(schedulerListener);
}
}
// Quitar el programadorListener
público booleano removeInternalSchedulerListener(SchedulerListener SchedulerListener) {
sincronizado (internalSchedulerListeners) {
devolver internalSchedulerListeners.remove(schedulerListener);
}
}
Lista pública<SchedulerListener> getInternalSchedulerListeners() {
sincronizado (internalSchedulerListeners) {
return java.util.Collections.unmodifiableList(new ArrayList<SchedulerListener>(internalSchedulerListeners));
}
}
public void notifySchedulerListenersScheduled (disparador de activación) {
for(escucha SchedulerListener: getInternalSchedulerListeners()) {
oyente.jobScheduled(activador);
}
}
public void notifyShedulerListenerUnScheduled (disparador de activación) {
for(escucha SchedulerListener: getInternalSchedulerListeners()) {
oyente.jobUnScheduled(activador);
}
}
}
ProgramadorOyente
Copie el código de código de la siguiente manera:
// Interfaz de escucha, función de devolución de llamada. El cliente debe proporcionar la implementación de la función de devolución de llamada al registrarse para el monitoreo.
interfaz pública SchedulerListener {
void jobScheduled (activador de activación);
void jobUnScheduled (activador de activación);
}
Desencadenar
Copie el código de código de la siguiente manera:
//Desencadenar
disparador de clase pública {
clave de activación de cadena privada;
nombre del activador de cadena privada;
Disparador público (Clave de activación de cadena, Nombre de activación de cadena) {
this.triggerKey = triggerKey;
this.triggerName = triggerName;
}
cadena pública getTriggerKey() {
devolver clave de activación;
}
setTriggerKey público vacío (String triggerKey) {
this.triggerKey = triggerKey;
}
cadena pública getTriggerName() {
devolver nombre del disparador;
}
setTriggerName público vacío (String triggerName) {
this.triggerName = triggerName;
}
cadena pública toString() {
return String.format("{triggerKey: %s, triggerName: %s}", triggerKey, triggerName);
}
}
Prueba
Copie el código de código de la siguiente manera:
Prueba de clase pública {
público estático vacío principal (String [] argumentos) {
QuartzScheduler qs = nuevo QuartzScheduler();
SchedulerListener oyenteA = nuevo SchedulerListener() {
@Anular
trabajo vacío públicoUnScheduled (activador de activación) {
System.out.println("escuchaUn trabajo no programado: " + trigger.getTriggerName());
}
@Anular
trabajo vacío público programado (activador de activación) {
System.out.println("escuchaUn trabajo programado: " + trigger.getTriggerName());
}
};
SchedulerListener oyenteB = nuevo SchedulerListener() {
@Anular
trabajo vacío públicoUnScheduled (activador de activación) {
System.out.println("trabajo de escuchaB no programado: " + trigger.getTriggerName());
}
@Anular
trabajo vacío público programado (activador de activación) {
System.out.println("trabajo de escuchaB programado: " + trigger.getTriggerName());
}
};
//Registrar oyente del programador
qs.addInternalSchedulerListener(oyenteA);
qs.addInternalSchedulerListener(oyenteB);
Trigger triggerA = new Trigger("Clave1", "triggerA");
Trigger triggerB = new Trigger("Clave2", "triggerB");
qs.scheduleJob(triggerA);
qs.scheduleJob(triggerB);
qs.unScheduleJob(triggerA);
}
}