While developing some kind of event monitoring Manager class i come across a problem of too many Object used : Each IEventDispatcher source can dispatch multiple eventNames, each eventName can have several function attached to it. The popular approach is using nested Dictionary/Object as the main data structure :
_sourceDict : Dictionary; /* map IEventDispatchers to _eventObjects */ _eventObject : Object; /* map eventName to _handlerDict */ _handlerDict : Dictionary; /* map handler to its params */
For faster check and overwrite the existed _handler for a specific source and eventName we need to use a Dictionary for _handlerDict instead of an Array, and by the way, add support for user parameters.
This data structure of course will still work without any problem even though the code looks busy by nested properties access. We might also got slow down by looping through those nested structure. Let’s have a look through another implementation where we save multiple values as the key instead of only one.
//how about :
function addListener(source, eventName, handler, params): void {
mkd.setValue(function (e: Event): void {
handler.apply(null, params);
}, source, eventName, handler); // --> value, key1, key2, key3
}
//instead of
function addListener(source, eventName, handler, params): void {
var evtObj : Object = _dict[ source] ||= {};
var handlerDict : Dictionary = evtObj[eventName] || new Dictionary();
handlerDict[handler] = function (e: Event): void {
handler.apply(null, params);
}
}
package vn.core.data
{
import flash.utils.Dictionary;
/**
* ...
* @author thienhaflash
*/
public class MultiKey
{
private var keys : Dictionary;
private var keyCnt : int;
private var key2Value : Dictionary; /* Object should also be fine here */
private function combineKeys(autoNew: Boolean, keyList: Array): Array {
if (!keys) return null;
var arr : Array = [];
var ckey : * ;
var l : int = keyList.length;
for (var i: int = 0; i <l; i++) {//keep the order !
ckey = keys[keyList[i]];
if (!ckey) { //skip zero !
if (autoNew) {
keys[keyList[i]] = ++keyCnt;
keys[keyCnt] = keyList[i];
ckey = keyCnt;
} else {
return null;
}
}
arr.push(ckey);
}
//arr.sort(Array.NUMERIC); /* so the key is unique */
return arr;
}
private function isValidKey(keys : Array, combine: Array): Boolean {
var l: int = combine.length;
for (var i: int = 0; i < l; i++) {
if (keys.indexOf(''+combine[i]) == -1) {//can not found some key
return false;
}
}
return true;
}
public function break2Key(s: String): Array {
var arr : Array = s.split('*');
for (var i: int = arr.length - 1; i > -1; i--) {
arr[i] = keys[arr[i]];
}
return arr;
}
public function removeValue(...keyList): * {
var s : String = combineKeys(false, keyList).join('*');
var value : * ;
if (s) {
value = key2Value[s];
delete key2Value[s];
}
return value;
}
public function filterValues(keyList: Array, returnValues: Boolean = true): Array {
var combined : Array = combineKeys(false, keyList);
var result : Array = [];
for (var s : String in key2Value) {
if (isValidKey(s.split('*'), combined)) {
result.push(returnValues ? key2Value[s] : s);
}
}
return result;
}
public function removeValues(keyList: Array, returnValues: Boolean = true): Object {
var combined : Array = combineKeys(false, keyList);
var result : Object = {};
for (var s : String in key2Value) {
if (isValidKey(s.split('*'), combined)) {
result[s] = key2Value[s];
delete key2Value[s];
}
}
return result;
}
public function getValue(...keyList): * {
var combined : Array = combineKeys(false, keyList);
return combined ? key2Value[combined.join('*')] : null;
}
public function setValue(value: *, ...keyList): void {
if (!keys) {
keys = new Dictionary();
key2Value = new Dictionary();
}
key2Value[combineKeys(true, keyList).join('*')] = value;
}
}
}