Anexsoft | Blog y dictado de cursos de Tecnología

En este encontrarás tutoriales de tecnología como PHP, ASP.NET MVC, Front-End, entre otros y cursos exigentes de modalidad online que te ayudarán a crecer profesionalmente.

Patrón Observador con Javascript (Observer Pattern)
Actualizado el 09 Noviembre, 2016 y leído 1,841 veces
Calificación: Sin calificar 10

Patrón Observador con Javascript (Observer Pattern)

Anexsoft

Muy bien, hoy vamos el patrón Observer en javascript el cual nos va a permitir conocer el estado actual de un objeto ante un cambio. ¿wHATT? .. tranquilo, sigue leyendo.

 

¿En qué consiste el patrón?

Permite observar los cambios que tenga un objeto (según especifiquemos). Por ejemplo, supongamos que tenemos una aplicación en javascript que permite dar un examen en línea y queremos registrar cada respuesta que el usuario vaya seleccionado. Mediante este patrón vamos a inyectar el comportamiento que queremos que tenga el objeto para este evento determinado y pueda mandar una petición AJAX al servidor para registrar las respuesta que se ha seleccionado.

Este patrón esta compuesto por un Sujeto y un Observador, el sujeto será la persona/cosa encargada de realizar una determinada acción y el observador será el encargado de vigilar lo que el sujeto haga.

 

Ejemplo práctico

Muy bien he hecho un ejemplo práctico en la que vamos a interceptar cuando 2 pokemons peleen y uno de ellos ganen, jaaaaa seguro esperabas el "ejemplo del examen online". Pues no, vamos hacer un ejemplo más práctico para poder comprender la lógica.

Observador

Lo primero que haremos es crear una clase llamada Observable

function Observable() {
    this.observers = [];

    this.add = function (observer) {
        this.observers.push(observer);
    };

    this.notify = function (obj) {
        this.observers.forEach(function (observer) {
            observer.call(null, obj);  
        });
    };
}

Esta clase nos va a permitir reutilizar código y dejar a un lado la odiosa tarea de copiar/pegar.

Sujeto

Luego tenemos nuestro sujeto que será el encargado de entablar combante entre 2 pokemons y determinar quien gano.

function PokemonCombate(pokemon1, pokemon2){
    this.observable = new Observable();

    this.pokemon1 = pokemon1;
    this.pokemon2 = pokemon2;
    this.ronda = 1;
}

Mediante prototype vamos a extender sus funcionalidades agregando la lógica del combate. Asimismo, este método tendrá la responsabilida de decirle a nuestro observador que ha habido un cambio de estado o en este caso un ganador en el combate.

PokemonCombate.prototype.combatir = function () {
  var ganador,
      perdedor;

  if(Math.floor((Math.random() * 2) + 1) === 1) {
      ganador = this.pokemon1;
      perdedor = this.pokemon2;
  } else {
      ganador = this.pokemon2;
      perdedor = this.pokemon1;
  }

  this.observable.notify({
    ganador: ganador,
    perdedor: perdedor,
    ronda: this.ronda
  });

  this.ronda++;
};

La lógica es muy simple, si el valor aleatorio arroja 1 pues gana el primer pokemon del caso contrario el otro.

 

Poniendo en práctica el código

Ahora debemos especificar el comportamiento que tenga nuestro Observador respecto al Sujeto.

var combate = new PokemonCombate('Pikachu', 'Meowth');

combate.observable.add(function(obj){
    console.log('El ganador de la ronda ' + obj.ronda + ' es: ' + obj.ganador)
});

Podemos agregar varios Observadores a nuestro Sujeto, supongamos que queremos mostrar tambíen quien perdió.

combate.observable.add(function(obj){
    console.log('El perdedor de la ronda ' + obj.ronda + ' es: ' + obj.perdedor)
});

 

¿Y no era más facil hacer esto?

PokemonCombate.prototype.combatir = function () {
  var ganador,
      perdedor;

  if(Math.floor((Math.random() * 2) + 1) === 1) {
      ganador = this.pokemon1;
      perdedor = this.pokemon2;
  } else {
      ganador = this.pokemon2;
      perdedor = this.pokemon1;
  }

  this.observable.notify({
    ganador: ganador,
    perdedor: perdedor,
    ronda: this.ronda
  });

    console.log('El ganador de la ronda ' + obj.ronda + ' es: ' + obj.ganador);
    console.log('El perdedor de la ronda ' + obj.ronda + ' es: ' + obj.perdedor)

  this.ronda++;
};

¿Se dieron cuenta?, es decir poner en el método combatir el código de la notificación. Si sería más práctico, pero tenemos un problema que estamos dandole alto acoplamiento a nuestro código y si quisieramos agregar mayor funcionalidad pues tendríamos que modificar ese código, en cambio de la manera que les planteo es más práctico y escalable, ya que podemos inyectar la lógica (inyección de dependencia) fuera de la clase haciendole más fácil de mantener a largo plazo.

La razón porque no es mejor trabajarlo de esta manera

Veamos un ejemplo, su desarrollador jr si entrará a la clase tendría que validar en que momento preciso tendrá que agregar el código de la notificación y en muchos escenarios reales el código no va ser tan sencillo como lo he planteado. Entonces, el programador jr hizo mal la validación y manda la notificación bajo la condición incorrecta. Ahora, si el programador jr sabe que tiene que agregar la notificación mediante el patrón observer se le será más sencillo porque su código se resumen a esto.

combate.observable.add(function(obj){
    console.log('El ganador de la ronda ' + obj.ronda + ' es: ' + obj.ganador)
});

 

Ejemplo completo

<script>
function Observable() {
  this.observers = [];

  this.add = function (observer) {
    this.observers.push(observer);
  };

  this.notify = function (obj) {
    this.observers.forEach(function (observer) {
      observer.call(null, obj);  
    });
  };
}

function PokemonCombate(pokemon1, pokemon2){
  this.observable = new Observable();

  this.pokemon1 = pokemon1;
  this.pokemon2 = pokemon2;
  this.ronda = 1;
}

PokemonCombate.prototype.combatir = function () {
    var ganador,
        perdedor;

  if(Math.floor((Math.random() * 2) + 1) === 1) {
      ganador = this.pokemon1;
      perdedor = this.pokemon2;
  } else {
      ganador = this.pokemon2;
      perdedor = this.pokemon1;
  }

  this.observable.notify({
    ganador: ganador,
    perdedor: perdedor,
    ronda: this.ronda
  });

  this.ronda++;
};

window.onload = function(){
  var combate = new PokemonCombate('Pikachu', 'Meowth');

  combate.observable.add(function(obj){
    document.getElementById("ganador").innerHTML = ('El ganador de la ronda ' + obj.ronda + ' es: ' + obj.ganador);
  });

  combate.observable.add(function(obj){
  	document.getElementById("perdedor").innerHTML = ('El perdedor de la ronda ' + obj.ronda + ' es: ' + obj.perdedor);
  });

  document.querySelector('#combate').addEventListener('click', function(){
    combate.combatir();
  })
}
</script>

<button id="combate">Combate!</button>
<div id="ganador"></div>
<div id="perdedor"></div>

¡Adquiera ya!

  • Software de Portafolio Profesional hecho en ASP.NET MVC 5 C#

    Software de Portafolio Profesional hecho en ASP.NET MVC 5 C#
  • Software de Venta e Inventario hecho en PHP y Codeigniter

    Software de Venta e Inventario hecho en PHP y Codeigniter
  • Código de fuente de Red Social desarrollada en ASP.NET MVC

    Código de fuente de Red Social desarrollada en ASP.NET MVC

Últimas publicaciones

Encuesta

¿Cómo nos conociste?

Síguenos

Estudia con nosotros y crece profesionalmente

Nuestros cursos han sido hecho en base a lo que demanda el mercado hoy en día.
La experiencia obtenida es la de un ambiente laboral.

Anexsoft
© 2017 Anexsoft, blog y cursos online de TI.