PDA

Просмотр полной версии : Перехват и исполнение


Ромастый
22.10.2006, 04:11
Как-то, еще давным-давно в эпоху mx2004, встала задача перехватывать вызов нужных методов каких-либо объектов, без того, чтобы прописывать в них бродкасты.
Набросал такой вот класс:
import mx.events.EventDispatcher;
import mx.utils.Delegate;
//
class EventInterceptor {
var _targ = new Object();
var _func:Function;
var _func_name:String;
private var dispatchEvent:Function;
public var addEventListener, removeEventListener:Function;
var onEvent:Function;
//
function EventInterceptor() {
EventDispatcher.initialize(this);
this.addEventListener("onEvent", this);
}
//
public function intercept(obj:Object, func:String):Void {
if (_targ && _func) {
dismiss();
}
_targ = obj;
_func_name = func;
_func = obj[func];
_targ[func] = Delegate.create(this, executeEvent);
}
//
public function dismiss():Void {
_targ[_func_name] = _func;
}
//
private function executeEvent():Void {
_func.apply(_targ, arguments);
dispatchEvent({type:"onEvent", target:_targ, event:_func_name});
}
}


Жуткий гибрид Делегата и ЕвентДиспетчера. Хых.. Написал и забыл.

Не так давно была тема по динамическому добавлению/удалению действий, к примеру, в onEnterFrame без полного переписывания.
Решил поэкспериментировать.
К примеру есть на сцене 2 клипа: mc1 и mc2

mc1.move = function() {
this._x += 20;
};
mc1.onEnterFrame = function() {
this.move();
};

EI1 = new EventInterceptor();
EI1.intercept(mc1, "move");
EI1.onEvent = function(evt_obj) {
_root.mc2._x += 2;
trace("1: "+this+" "+evt_obj.target+" "+evt_obj.event);
};
//
EI2 = new EventInterceptor();
EI2.intercept(mc1, "move");
EI2.onEvent = function(evt_obj) {
_root.mc1._y += 2;
trace("2: "+this+" "+evt_obj.target+" "+evt_obj.event);
};
//
EI3 = new EventInterceptor();
EI3.intercept(mc1, "move");
EI3.onEvent = function(evt_obj) {
_root.mc2._y += 2;
trace("3: "+this+" "+evt_obj.target+" "+evt_obj.event);
};

Плюсы такого подхода:
Экземпляры интерсептора перехватывают вызов метода move, и выполняют свои действия. Все ок.

Но. Минусы:
1. Все перехваты осуществляются последовательно, а не независимо. То есть следующий интерсептор перехватывает не mc1.move, как казалось бы, а делегат предыдущего.
2.Вытекает из первой. Если мы удаляем предыдущий перехватчик, то и следующий за ним тоже перестает работать.

Вопрос: может кто делал что-то подобное и как-то еще решал такую задачу?

etc
22.10.2006, 14:48
Я долго пытался понять, что ты хочешь сделать и почему нельзя тупо заменить (дать ссылку) move другим методом, а?

Ромастый
22.10.2006, 21:10
Гм... Наверное привел не очень наглядный пример.
Будем перехватывать не move, а onEnterFrame:
EI1.intercept(mc1, "onEnterFrame");
EI2.intercept(mc1, "onEnterFrame");
EI3.intercept(mc1, "onEnterFrame");
На исходном onEnterFrame клипа mc1 висит только движение по оси x этого клипа (код в предыдущем посте). Создание трех перехватчиков добавляет еще три движения (по осям y и x обоих клипов). То есть формально мы динамически добавляем в onEnterFrame новые действия без того, чтобы его переписывать.
Но фактически, повторюсь, каждый последующий экземпляр перехватывает не mc1.onEnterFrame, как мы вроде бы написали, а всего лишь предыдущий по цепочке.
Проблемы возникнут, когда мы захотим удалить какое-то действие из onEnterFrame - перестанут работать и все последующие.

Вот и любопытно, какие есть соображения по поводу, как эту дрянь переделать так, чтобы перехваты шли независимо, а не последовательно. :umnik2:

etc
22.10.2006, 21:17
А чем не устраивает подписка/отписка методов на события?
Делаешь мувик вещателем, ставишь на onEnterFrame dispatchEvent({type:'onEnterFrame'}), затем добавляешь mc.addEventListener('onEnterFrame',anyMethod1); и т.д.

Ромастый
22.10.2006, 21:17
Вообще в свое время EventInterceptor создавался для других целей, как вспомогательный класс.
Но захотелось попробовать его и в таком аспекте. Тогда и столкнулся с вышеописанной проблемой... Есть соображения, как исхитриться это сделать именно в таком варианте, или же только кардинально другим подходом можно?

Ромастый
22.10.2006, 21:19
Вот. Как раз тогда задача стояла перехватывать вызов любых методов, без инициализации перехватываемых объектов, и вообще любого вмешательства в код извне.

Ромастый
22.10.2006, 21:24
Поясню, почему это нужно было.
Как один из примеров: в контексте той задачи некоторые объекты могли инициализироваться Диспетчером или другим бродкастером уже после того, как требовалось отслеживать вызов их методов.
Вторая причина наверное носила скорее принципиальный характер. Перехватывать вызов без вмешательства в код. То есть дописывать бродкасты в каждом методе. А их мог быть не один десяток.

etc
22.10.2006, 21:27
Что мешает переназначить onEnterFrame на другой метод и в нём убирать/добавлять вызываемые методы?
Одновременно выполнить все методы на одном событии невозможно в принципе.

silin
22.10.2006, 21:27
я бы по-простому сделал :
Object.prototype.addFunc=function(func:String,toAdd:Function){
if(!this._adds){
this._adds=[];
this.naitiveFunc=this[func];
this[func]=function(){
this.naitiveFunc();
for(var i in this._adds)this._adds[i]();
}
}
this._adds.push(toAdd);
}

mc1.move = function() {
this._x += 20;
};
mc1.onEnterFrame = function() {
this.move();
};
mc1.addFunc("move",function(){
_root.mc2._x += 2;
});

mc1.addFunc("move",function(){
_root.mc2._y += 2;
});

Ромастый
22.10.2006, 21:52
to __etc: Да в принципе ничего не мешает :confused:
Сделать компромиссное решение с тем, что предложил silin.

to silin: про добавление в массив тоже приходила мысля в голову. Правда в этом варианте еще придется отслеживать порядковые номера в массиве, чтобы удалять или перемещать нужные действия.
ТОгда как с независимыми экземплярами интерсептора мы уже сразу имеем прямые ссылки на них.

Так что действительно, тут придется прибегать к компромиссному решению. Оставаясь в контексте исходной задачи (не меняя исходный код и не делая перехватываемый объект вещателем) вешать на одно событие (или метод) один перехватчик. А уже на onEvent перехватчика - работу по добавлению/удалению действий в массив.