Observer pattern
Uno de los mas importantes patterns de diseno es Observer, este patron lo podemos ver en librerias como Reactive Extensions, React, Redux, Angular y varias librerias relacionadas con streaming, pero a veces no queremos toda una libreria porque nuestro requerimiento no es tan complejo, y escribir un simple Observer no es tan complicado, al menos no en Kotlin.
El modo de funcionar es bastante simple, tenemos un distribuidor de eventos y varios listeners cada vez que hay un evento, el distribuidor se encarga de enviar el evento a todos los que esten suscritos, es como crear un mini service bus.
https://en.wikipedia.org/wiki/Observer_pattern aqui hay una explicacion mucho mas detallada
Basicamente necesitamos 3 cosas, los suscriptores, una lista de suscritos y una forma de recibir y propagar eventos, vamos a implementar esto en kotlin;
El codigo
Para la lista de suscripciones solo creamos una lista de funciones, cada vez que alguien quiera escuchar agrega una funcion que recibira el modulo que hizo el evento, el tipo de evento y los datos relacionados. Finalmente tenemos el emisor, que propaga los eventos a todas las funciones de la lista. Como adicional creamos un cancelador de suscripcion, por si queremos dejar de recibir eventos.
private var handlers: List<(module: String, event: String, data: HashMap<String, Any>) -> Any> = emptyList()
fun subscribe(subscriber: (module: String, event: String, data: HashMap<String, Any>) -> Any) {
handlers = handlers + subscriber
}
fun unsubscribe(subscriber: (module: String, event: String, data: HashMap<String, Any>) -> Any) {
handlers = handlers.filter {
it != subscriber
}
}
fun emit(module: String, event: String, data: HashMap<String, Any>) {
handlers.forEach {
it.invoke(module, event, data)
}
}
}
Usando el Observer
Un pequeno ejemplo de como usar nuestro ejemplo:
val obs = basicObserver()
val subscriber = { module: String, event: String, data: HashMap<String, Any> ->
println(module)
println(event)
println(data)
}
val subscriber2 = { module: String, event: String, data: HashMap<String, Any> ->
println("dos $module")
println("tres $event")
println(data)
}
obs.subscribe(subscriber)
obs.subscribe(subscriber2)
obs.emit("hello", "world", hashMapOf("java" to "mexico"))
println("")
obs.unsubscribe(subscriber)
obs.emit("new", "world", hashMapOf("java" to "mexico"))
}
creamos dos Suscribers, nos suscribimos al observer y luego emitimos modulo "hello" . evento "world" y un hasmap con java: mexico, despues desuscribimos la primera suscripcion y emitimos el segundo evento con modulo "new" . evento "world" y un hasmap con java: mexicodos.
La salida de esto es:
world
{java=mexico}
dos hello
tres world
{java=mexico}
dos new
tres world
{java=mexicodos}
Justo lo que estabamos esperando las dos salidas para el primer evento porque tenemos dos subscriptores y la segunda salida solo para el segundo suscriptor.
Cuando usar esto?
Los observers son importantisimos si quieres saber que algo pasa en tu codigo sin estar esperando a que suceda, si necesitas programacion asyncrhona sirve para avisar que algo ya paso y no bloquear el thread, para escuchar eventos, si usas GUI para escuchar cualquier evento de la pantalla, para leer un archivo y saber cuando este termino de ser procesado, con algunas mejoras puedes usarlos para coordinar threads, etc.
En javascript que todo es asynchrono, tambien ayuda mucho asi que aqui hay un ejemplo:
this.handlers = [];
this.subscribe = fn => {
this.handlers.push(fn);
};
this.unsubscribe = fn => {
this.handlers = this.handlers.filter(item => item !== fn);
};
this.emit = (m, t, o, thisObj) => {
const scope = thisObj;
this.handlers.forEach(item => item.call(scope, m, t, o));
};
}
const observer = new basicObserver();
const subscriber1 = (module, event, data) => {
console.log(module);
console.log(event);
console.log(data);
};
const subscriber2 = (module, event, data) => {
console.log(module + 'dos');
console.log(event + 'dos');
console.log(data);
};
observer.subscribe(subscriber1);
observer.subscribe(subscriber2);
observer.emit('hello', 'world', {
java: 'mexico'
});
observer.unsubscribe(subscriber2);
observer.emit('new', 'world', {
java: 'mexicodos'
});
la salida
world
{ java: 'mexico' }
hellodos
worlddos
{ java: 'mexico' }
new
world
{ java: 'mexicodos' }
Podrias usar Custom events en javascript pero la desventaja es que no todos los browsers lo soportan y eventos simples no puedes enviarlos con informacion adicional
- betotto's blog
- Inicie sesión o regístrese para enviar comentarios
Comentarios recientes
hace 2 semanas 4 días
hace 2 semanas 4 días
hace 2 semanas 4 días
hace 27 semanas 6 horas
hace 28 semanas 2 días
hace 34 semanas 6 días
hace 1 año 27 semanas
hace 2 años 39 semanas
hace 2 años 43 semanas
hace 2 años 50 semanas