1

Is there built in functionality to make eventable types in dart?

In my Javascript applications I use a class called Eventable to provide the following functionality:

var dog = new Dog() //where Dog inherits from Eventable
var cat = new Cat() //where Cat inherits from Eventable

//use 'on' to listen to events
cat.on(dog, 'bark', cat.runaway); //assuming Cat has a method runaway on its prototype

//use fire to launch events
dog.fire({type: 'bark'});  //this causes cat.runaway(event); to be called

A very common pattern in javascript, I like it because it helps me to keep objects isolated in the src and in my mind.

Using the on method creates a new EventContract which has a unique key based on the owner (cat above), client (dog above), type ('bark' above) and function (cat.runaway above). This unique key allows me to ensure that no duplicated EventContracts are created, but more importantly it allows me to keep an easy to lookup collection of all of the EventContracts an object has, such that I can call:

cat.dispose();

and all of the event contracts for cat will be destroyed, so I am confident that all of the external references to cat have been deleted and cat can now be GC'd.

But I am finding it hard to implement this functionality in Dart, because doing something like: cat.on(dog, 'bark', cat.runaway); causes a new function to be generated to enclose (){cat.runaway();} and the only unique key I can get off of a standard function object in dart is its hashCode, but that means I can recall cat.on(dog, 'bark', cat.runaway); and it will create a new EventContract because it has created another unique closure rather than processing a reference to the original function, as happens in javascript.

Is there anyway for me to achieve this pattern in dart?

4

1 回答 1

7

通常,您应该使用Stream惯用的方式在 Dart 中提供一系列事件。此外,最好在源上明确声明事件(例如onBark,而不是on['bark']. 这样的事情应该让你开始:

class Dog {
  var _barkController = new StreamController();
  Stream get onBark => _barkController.stream.asBroadcastStream();
  void bark() => _barkController.add("woof");
}

class Cat {
  void runaway() => print("cat running");
}

void main() {
  var dog = new Dog();
  var cat = new Cat();

  // listen returns subscription object which you can use to unsubscribe
  var sub = dog.onBark.listen((event) => cat.runaway()); 

  dog.bark();  // prints 'cat running'
  sub.cancel();
  dog.bark();  // doesn't print anything
}

如果你更喜欢动态声明事件,你可以有这样的东西:

  var sub = dog.on['bark'].listen((event) => cat.runaway()); 
  // in this case `on` is a property of some Events type which overrides
  // operator[] to return appropriate Stream

已经有一个类似的事件类,用于在 DOM 元素上提供浏览器事件。

此外,还有社区库event_streamevent_source可以稍微简化此任务。

于 2013-05-09T16:08:04.567 回答