2012-01-31 14 views
9

Me gustaría usar eventos para comunicarme entre mis objetos en un entorno de cierre de google (GC).Crear eventos con google closure

Supongamos que tengo dos clases foobar.Boss y foobar.Employee. El Jefe quiere saber cuándo el Empleado ha hecho café, y si ese café es descafeinado (está descartando la cafeína esta semana).

GC ha hecho las clases disponibles que parecen proporcionar los medios para hacer esto, goog.events.Event y goog.events.EventTarget.

Sin conocer mejor, pensaría que sería el siguiente:

foobar.Employee.prototype.makeCoffee = function(isDecaf) 
{   
    this.coffeeMaker.putCoffeeInMachine(isDecaf); 
    this.coffeeMaker.start(); 
    var event = new goog.event.Event('COFFEE_ON', { isDecaf: isDecaf }); 
    goog.events.dispatchEvent(event); 
} 

foobar.Boss.prototype.addEmployee = function(employee) 
{ 
    ... 
    goog.events.listen(employee, 'COFFEE_ON', function(e) 
    { 
     if (e.target.isDecaf) 
     { 
      this.refillMug(); 
     } 
    }, false, this); 
    ... 
} 

Es este un patrón correcto? Estoy confundido por la clase goog.events.EventTarget - ¿cómo despacha un objetivo los eventos? ¿Un objetivo no le ha sucedido nada?

This question es útil, pero se agradecería una respuesta más directa.

+0

http://code.google.com/p/closure-library/source/browse/trunk/closure/goog/fx/fx.js?r=2 # 582 Es una implementación de ejemplo: heredar de goog.events.EventTarget parece extraño (¿es completamente necesario que Employee extienda EventTarget?) –

Respuesta

9

Habiendo mirado esto por un tiempo, mi comprensión es ahora que el EventTarget de hecho juega un doble rol de ser la entidad que despacha los eventos y la entidad que se escucha. Entonces, una opción sería tener Employee heredar goog.events.EventTarget pero he tomado una ruta diferente.

Primero creé un nuevo tipo de evento que le informaría al Jefe si el café era descafeinado.

/** 
* @constructor 
* @extends {goog.events.Event} 
*/ 
foobar.CoffeeEvent = function(isDecaf) 
{ 
    goog.events.Event.call(this, 'COFFEE_ON'); 
    this.isDecaf = isDecaf; 
}; 
goog.inherits(foobar.CoffeeEvent, goog.events.Event); 

Siguiente He creado un tipo de escucha de eventos para enviar estos eventos.

/** 
* @constructor 
* @extends {goog.events.EventTarget} 
*/ 
foobar.CoffeeEventTarget = function() 
{ 
    goog.events.EventTarget.call(this); 
}; 
goog.inherits(foobar.CoffeeEventTarget, goog.events.EventTarget); 

He añadido un objeto de este tipo a mi Employee.

foobar.Employee = function() 
{ 
    ... 
    this.coffeeEvents = new foobar.CoffeeEventTarget(); 
    ... 
} 

Cuando el empleado vuelve a llenar el café:

foobar.Employee.prototype.makeCoffee = function(isDecaf) 
{   
    this.coffeeMaker.putCoffeeInMachine(isDecaf); 
    this.coffeeMaker.start(); 
    var event = new foobar.CoffeeEvent(isDecaf); 
    this.coffeeEvents.dispatchEvent(event); 
} 

Sr. Bossman escucha para esto.

foobar.Boss.prototype.addEmployee = function(employee) 
{ 
    ... 
    goog.events.listen(employee.coffeeEvents, 'COFFEE_ON', function(e) 
    { 
     if (e.isDecaf) 
     { 
      this.refillMug(); 
     } 
    }, false, this); 
    ... 
} 

Tenga en cuenta que esto no me va a decir lo que empleado volvió a llenar el café, debido a que el objetivo del evento será una instancia de CoffeeEventTarget. Si quería todo Employee allí, supongo que podría agregarlo como campo de miembro. Si está bien heredar al Employee desde goog.events.EventTarget, obtiene Employee gratis como destino.

+0

foobar.CoffeeEvent probablemente debería aceptar un tipo, en lugar de tenerlo codificado. Este sería un buen uso para una enumeración. –

+0

Todavía estoy mirando esto. Probablemente no haya una necesidad real en mi caso de subclase EventTarget. –

1

La forma en que pienso de EventTarget es la siguiente:

Un botón es un objetivo, que puede registrarse para ser notificado sobre su evento de clic cada vez que se lleva a cabo. Por lo tanto, el "objetivo" de un clic es el botón (apunta al botón, luego haga clic en él). Pero cuando se hace clic en el botón, no es el mouse el que le dice a todos que se hizo clic en el botón; el botón en sí despacha ese mensaje.

para tocar sobre la cuestión planteada por @ ben-Flynn acerca ¿por qué alguien necesita/quiere subclase EventTarget:

Si desea escuchar tecla abajo eventos, es probable que se preocupa por lo la tecla fue presionada La forma en que sabría qué tecla se presionó es buscar el campo de código de clave en el objeto que es enviado por KeyDownEventTarget. Por otro lado, un objeto ButtonEventTarget distribuye un objeto de evento diferente, concretamente un evento ClickEvent, que no tiene un campo de código clave. Entonces, para resumir, la razón por la que subclase EventTarget es para que quien esté escuchando eventos que serán enviados por ese objetivo sepa qué objeto de evento se enviará cuando se desencadene el evento.

0

Así es como yo lo haría ...

Vamos a crear un tipo de café. Si tuviéramos que llevar esto más allá, podríamos tener una clase base de Café y luego clasificarla con una clase DecafCoffee. Pero vamos a mantener las cosas simples.

foobar.Coffee.js

/** 
* @fileoverview Coffee class 
*/ 

goog.provide('foobar.Coffee'); 

/** 
* @constructor 
*/ 
foobar.Coffee = function(){ 
    //... 
}; 

Nuestra clase empleado debe implementar goog.events.EventTarget para poder distribuir eventos. No debe olvidar llamar al constructor padre con goog.base o goog.events.EventTarget.call ya que esto configurará las variables internas que la clase necesita.

foobar.Employee.js

/** 
* @fileoverview Implements the Employee class 
*/ 

goog.provide('foobar.Employee'); 
goog.require('goog.events.EventTarget'); 
goog.require('foobar.Coffee'); 

/** 
* @constructor 
*/ 
foobar.Employee = function(){ 
    // Calls the parent class (goog.events.EventTarget) 
    goog.base(this); 
}; 
goog.inherits(foobar.Employee, goog.events.EventTarget); 

/** 
* Make a coffee 
*/ 
foobar.Employee.prototype.makeCoffee = function(){ 
    // Determine what coffee type to make ... 
    // Create the coffee 
    var coffee = new foobar.Coffee(); 
    this.dispatchEvent({ 
     type: "decaf_coffee", 
     target: coffee 
    }); 
}; 

La clase patronal no tiene que hacer nada especial, ya que no se despacha eventos. Solo necesita un método #drinkCoffee() al que podamos llamar.

foobar.Boss.js

/** 
* @fileoverview Implements the Boss class 
*/ 

goog.provide('foobar.Boss'); 

/** 
* @constructor 
*/ 
foobar.Boss = function(){ 
    //... 
}; 

/** 
* Make this boss drink coffee 
* @param {foobar.Coffee} coffee The coffee to drink 
*/ 
foobar.Boss.prototype.drinkCoffee = function(coffee){ 
    //.... 
}; 

Este es el principal código JavaScript, que se le ejecuta, puede colocar donde quieras, por ejemplo, en línea en el navegador o en su propia secuencia de comandos.

main.js

goog.require('foobar.Boss'); 
goog.require('foobar.Employee'); 
goog.require('goog.events'); 

// Jane is the boss of Sam, but we will use lower case as I typically 
// only capitalise the first letter to indicate a constructor. 
var jane = new Boss(); 
var sam = new Employee(); 

// Set up event listening 
goog.events.listen(sam, "decaf_coffee", function(e){ 
    var coffee = e.target; 
    // We've got the decaf coffee Sam made, now Jane can enjoy drinking it 
    jane.drinkCoffee(coffee); 
}, false, this); 

// Tell Sam to make a coffee 
sam.makeCoffee(); 
Cuestiones relacionadas