最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Creating events with google closure - Stack Overflow

programmeradmin3浏览0评论

I would like to use events to municate between my objects in a google closure (GC) environment.

Suppose I have two classes foobar.Boss and foobar.Employee. The Boss wants to know when the Employee has made coffee, and whether or not that coffee is decaf (he's laying off the caffeine this week).

GC has made classes available that seem to provide the means to do this, goog.events.Event and goog.events.EventTarget.

Without knowing better, I'd think it would work like this:

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);
    ...
}

Is this a correct pattern? I am confused by the class goog.events.EventTarget -- how does a target dispatch events? Doesn't a target have things happen to it?

This question is helpful, but a more direct answer would be appreciated.

I would like to use events to municate between my objects in a google closure (GC) environment.

Suppose I have two classes foobar.Boss and foobar.Employee. The Boss wants to know when the Employee has made coffee, and whether or not that coffee is decaf (he's laying off the caffeine this week).

GC has made classes available that seem to provide the means to do this, goog.events.Event and goog.events.EventTarget.

Without knowing better, I'd think it would work like this:

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);
    ...
}

Is this a correct pattern? I am confused by the class goog.events.EventTarget -- how does a target dispatch events? Doesn't a target have things happen to it?

This question is helpful, but a more direct answer would be appreciated.

Share Improve this question edited May 23, 2017 at 12:23 CommunityBot 11 silver badge asked Jan 31, 2012 at 22:45 Ben FlynnBen Flynn 18.9k21 gold badges101 silver badges143 bronze badges 1
  • code.google./p/closure-library/source/browse/trunk/closure/… Is an example implementation -- inheriting from goog.events.EventTarget seems strange (is it pletely necessary that Employee extends EventTarget?) – Ben Flynn Commented Jan 31, 2012 at 23:40
Add a ment  | 

3 Answers 3

Reset to default 10

Having looked at this for a while, my understanding is now that the EventTarget in fact plays a dual roll of being the entity that dispatches events and the entity that is listened to. So one option would be to have Employee inherit goog.events.EventTarget but I have gone a different route.

First I created a new event type that would let the Boss know if the coffee was decaf.

/**
 * @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);

Next I created an event listener type to dispatch these events.

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

I added an object of this type to my Employee.

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

When the employee refills the coffee:

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

Mr. Bossman listens for this.

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

Note that this won't tell me which employee refilled the coffee, because the event target will an instance of CoffeeEventTarget. If you wanted all of Employee in there I suppose you could add it as a member field. If you were OK with inheriting to Employee from goog.events.EventTarget then you get Employee for free as the target.

The way I think of EventTarget is this:

A button is a target, which you can register to be notified about its click event whenever one takes place. Thus, the "target" of a click is the button (you aim at the button, then click on it). But when the button gets clicked, it's not the mouse that tells everyone that the button was clicked - the button itself dispatches that message.

To touch on the question brought up by @ben-flynn about why would someone need/want to subclass EventTarget:

If you want to listen for key down events, you probably care about what key was pressed. The way you'd know what key was pressed is by looking up the keyCode field on the event object that is dispatched by the KeyDownEventTarget. On the other hand, a ButtonEventTarget dispatches a different event object, namely a ClickEvent, which does not have a keyCode field in it. So to summarize, the reason you'd subclass EventTarget is so whoever is listening for events that will be dispatched by that target know what event object will be dispatched when the event is triggered.

Here's how I would do it...

Let's set up a coffee type. If we were to take this further we could have a base Coffee class and then sub class it with a DecafCoffee class. But lets keep things simple.

foobar.Coffee.js

/**
 * @fileoverview Coffee class
 */

goog.provide('foobar.Coffee');

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

Our Employee class must implement goog.events.EventTarget to be able to dispatch events. You mustn't forget to call the parent constructor with goog.base or goog.events.EventTarget.call either as this will setup internal variables the class needs.

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
    });
};

The boss class doesn't need to do anything special as it won't be dispatching events. It just needs a #drinkCoffee() method we can call.

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){
    //....
};

This is the main JavaScript code which you'll be running, you can put wherever you like, e.g. inline in the browser or in its own script.

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();
发布评论

评论列表(0)

  1. 暂无评论