2

オブジェクトのメンバーの変更を追跡するための一般的なメカニズムについて考えています。アイデアは基本的に、 aが呼び出されるlastModifiedたびにタイムスタンプを一部のメンバーに保存することです。set

これまでの私の考えは、いくつかの親クラスを持つことでした(疑似コードはこちら)

class Tracker {
    time lastModified;
    void onChildSet() {
        lastModified = NOW();
    }
}

そして、私の特定のオブジェクトのためにこれから継承する

public class Object extends Tracker {
    sometype member;
    void setMember(sometype value) {
        member = value;
        onChildSet();
    }
}

このアプローチについて私が気に入らないのはonChildSet()、親クラスからの明示的な呼び出しの必要性を回避する方法がわからないことです。lastModified実際、コードを書かなくても自動的に更新する方法を探しています。これを達成する方法はありますか?

4

2 に答える 2

1

ほとんどの動的言語には、メソッド呼び出しをインターセプトする何らかの方法があります。たとえば、すべての ruby​​ オブジェクトには、定義されていないオブジェクトでメソッドが呼び出されるたびに呼び出されるメソッド「method_missing」があります。この機能を使用して、lastModified 値を追跡するプロキシ オブジェクトを設定できます。別の動的言語である Actionscript 3.0 にはProxyがありますAPI のクラス。繰り返しますが、このプロキシ クラスを使用して関数呼び出しをインターセプトできます。残念ながら、このようなプロキシを使用すると、メソッドの定義方法を変更する必要があります。ruby の場合、明らかに method_missing はメソッドが存在しない場合にのみ呼び出されます。これが意味することは、プロキシ クラスによってラップされるオブジェクトにメソッドを定義する必要があるということです。私が AS3 にまとめた例を見てください。プロパティを追跡するには、trackSet メソッドを使用して定義する必要があります。このメソッドを MyObject クラスで直接定義することはできません。trackSet は、プロパティの名前をオブジェクトとコールバック関数に格納します。プロキシ クラスで setProperty が呼び出されると、プロパティの名前が setters オブジェクトに対してチェックされ、存在する場合はそのプロパティの lastModified が更新され、そのプロパティ コールバックが呼び出されます。

package {

    import flash.utils.Proxy;
    import flash.utils.flash_proxy;

    public dynamic class Tracker extends Proxy {

        private var setters : Object;

        public function Tracker() { 
            setters = { };
        }

        public function getLastModified(name : String) : Number {
            return setters[name] ? setters[name].lastModified : 0;  
        }

        protected function trackSet(name : String, fn : Function) : void {
            setters[name] = {
                lastModified: 0,
                setter: fn
            };
        }

        override flash_proxy function setProperty(name : *, value : *) : void {
            if(!setters[name]) return;
            setters[name].lastModified = new Date().time;
            setters[name].setter(value);
        }

    }
}

-

package {

    public dynamic class MyObject extends Tracker {

        public function MyObject() {
            trackSet('member', setMember);
        }

        private function setMember(val : String) : void {
            trace('set member =', val);
        }

    }
}

-

var obj : MyObject = new MyObject();
obj.member = 'monkey';
trace('member getlast modified at', obj.getLastModified('member'));
于 2012-08-09T17:35:22.723 に答える
1

InvocationHandler を使用します。バイトコードのインストルメンテーションを使用して自分で同じことを行うこともできますが、 InvocationHandler の方が簡単です

于 2012-08-08T21:05:22.633 に答える