5

マウスイベントのクラスがあります。Dojo b/c を使用しています。その OO アプローチが気に入っています。

dojo.declare("MouseObject", null, {
  constructor: function(){},
  onclick : function(){...},
  _onClick : function(){...}
});

_onClick()ウィンドウで生成されたマウスのプレス/リリース イベントをリッスンし、クリックが発生したかどうかを判断します。ある場合onClick()は呼び出されます。onClick()可能なすべてのクリックに共通の機能を実行するため、ユーザーがクリックするたびに呼び出す必要があります。

場合によっては、ユーザーがの機能を拡張したい場合がonClick()あります。元の機能をコピーペーストせずに組み込む方法はありますか? 私が考えることができる2つの方法は、どちらも好きではありません

dojo.declare("MouseObjectChild", [MouseObject], {
  constructor: function(){},
  onclick : function(){this.inherited(arguments);...}
});

これには、実際には必要のない新しいクラスを作成し続けなければならないという欠点があり、2 つの中間関数を追加する必要があります。

dojo.declare("MouseObject", null, {
      constructor: function(){},
      onclick : function(){this._onClick()...}, //child onClick
      _onClick : function(){...}, //parent onClick
      __onClick : function(){...} //listener
    });

しかし、これは良いコードのようには見えません


報奨金に関しては、プログラムとユーザーの相互作用に対処する最善の方法について専門家のアドバイスが必要です。プログラムがキャンバスに円を描くなどの重要な機能を提供する場合、ユーザーはそれをどのように操作するのが最善でしょうか。ユーザーが円の後ろに三角形を描きたい場合はどうすればよいでしょうか? 丸の前に四角?次に、プログラムは次のような pre および post メソッドを提供する必要があります。

beforeDraw();
draw();
afterDraw();

これは良い設計と見なされますか? 代わりに、関数ポインタを配列に入れて順番に呼び出す必要がありますか?

4

6 に答える 6

1

いくつかのオプションがあります。
1. Promise パターンの人気が高まっています (ただし、競合する仕様があります): http://wiki.commonjs.org/wiki/Promises/B . jQuery には B に近い実装があり、十分に文書化されています。最も多くのオプションがあり、堅牢ですが、最初は頭を包み込むのは簡単ではありません.

  1. AOP スタイルのプログラミングでは、アドバイスの前後をいじることができます。ただし、それを機能させるには、すべてを匿名関数に入れるのをやめ、インスタンス化後にアドバイスを適用するか、機能をクラスに焼き付けて使用する計画を立てるかを決定する必要があります。これにはコード構造の計画が必要ですが、多くのユーティリティが提供されます。

例えば:

var MYAPP = {
  onClick: function () {
    //do something...
  }
};

dojo.declare("MouseObject", null, {
  constructor: function(){},
  onclick : function(){...},
  _onClick : function(){
    return MYAPP.onClick.apply(this, arguments);
  }
});

私のクラスは毎回 MYAPP を呼び出すので (そうです、これにはスコーピング料金がかかります)、MYAPP からぶら下がっている関数を操作することができ、それを使用する人は誰でも恩恵を受けることができます。

MYAPP.after("onClick", function () {...}); //lots of ways to write .after, just google some AOP js or use a library

反対側:

var MYAPP = {
  onClick: function () {
    //do something...
  }
};

dojo.declare("MouseObject", null, {
  constructor: function(){},
  onclick : function(){...},
  _onClick : MYAPP.onClick
});

関数が参照によって MouseObject に渡されたため、MYAPP を変更して MouseObject またはそのインスタンスの変更を確認することはできません。インスタンスを AOP でのみ変更できます (または、クラスのプロトタイプを変更することにより、将来のすべてのインスタンスを変更できます)。

何かのようなもの:

var m = new MouseObject();
m.after("onClick", function () {...}); //you need to add .after to your class or use an apply pattern from library code

特定のインスタンス、将来のすべてのインスタンス (オフになるまで)、またはすべてなど、どのように使用されるかによって異なります。

  1. 「イベントキュー」が提案されました。これは、オブジェクトの配列とキュー マネージャーを使用してタスクを管理するアクティブ オブジェクト パターンに似ています。これは実装が最も簡単ですが、キューが「詰まって」処理されなくなるという欠点がいくつかあります。私が作成した iPhone アプリに基づいて、proto-q (http://code.google.com/p/proto-q/) と呼ばれるこのタイプの管理用のライブラリを作成しました。それは私にとってはうまくいきましたが、万人向けではありません。
于 2011-11-02T12:39:48.110 に答える
1

「関数を独自の配列に入れて順番に呼び出すべきか」や「独自のイベント システムを構築するべきか」というアイデアで示唆されているように、拡張されたパッケージにバンドルされているdojox.lang.aspectライブラリを確認することをお勧めします。標準ライブラリ。これは基本的に、「dojo.connect」ソリューションのより高度なバージョンである必要があります。

dojo.require('dojox.lang.aspect');
var aop = dojox.lang.aspect;

function log(msg){ return function(){
    console.log(msg);
};}

var obj = {
   draw : log('draw circle');
};

obj.foo();
//prints
//  draw circle

aop.advise(obj, 'draw', [
    {before: log('draw triangle')},
    {after: log('draw a square')},
    {after: log('done!')}
]);

obj.foo();
//prints
//  draw a triangle
//  draw a circle
//  draw a square
//  done!
于 2011-11-02T14:07:04.753 に答える
1

onclick() が呼び出されたときにコードを実行したい場合は、それに接続するだけです。dojo.connect() を使用すると、イベントだけでなく関数呼び出しにも接続できることに注意してください。

dojo.connect(obj, 'onclick', function(){
  // Some extra code that runs when obj.onclick() is called
});

彼が新しいクラスを作成して機能を拡張したい場合は、呼び出しthis.inherited(arguments);が最善の方法です。

于 2011-05-30T16:41:29.420 に答える
1

独自の単純なイベント モデルを作成してみませんか?

// store our callbacks
var hooks = {};

// add a callback
var hook = function(name,fn){
  if(typeof hooks[name] === 'undefined'){
    hooks[name] = [];
  }
  hooks[name].push(fn);
  return true;
};

// remove a callback
var unhook = function(name,fn){
  if(typeof hooks[name] === 'undefined'){ return false }
  var i, u = hooks[name].length;
  for(i=0;i<u;i++){
    if(hooks[name][i] === fn){
      hooks[name].splice(i,1);
      return true;
    }
  }
};

// trigger a callback
var callHook = function(name, data){
   if(typeof hooks[name] === 'undefined'){ return false }
   var i, u = hooks[name].length;
   for(i=0;i<u;i++){
     hooks[name][i](data);
   }
};

その後(例はコンテキストを渡します):

hook('beforeDraw',function(ctx){ 
  console.log('I am called prior to drawing');
});

hook('afterDraw',function(ctx){
  console.log('I am called after drawing');
});

var drawCircle = function(){
  callHook('beforeDraw', ctx);
  // drawing code here
  callHook('afterDraw', ctx);
};

または、スコープをコールバックに渡したい場合は、callHookメソッドをスコープ引数を受け入れるように変更してから、callまたはを使用して、または他のオブジェクトapplyを渡すことができます。this

var callHook = function(name, scope, data){
   if(typeof hooks[name] === 'undefined'){ return false }
   var i, u = hooks[name].length;
   for(i=0;i<u;i++){
     hooks[name][i].call(scope, data);
   }
};

// later
var drawCircle = function(){
   callHook('beforeDraw', this, ctx);
   // or
   callHook('beforeDraw', someObject, ctx);
};

イベントモデル関数を定義する方法と場所に応じて、オブジェクトの特定のインスタンス、オブジェクトのすべてのインスタンス、グローバルなどに機能をスコープできます。これらのコールバックをどのように割り当て、変更、トリガーするかによって異なります。

于 2011-10-31T15:08:26.297 に答える
0

__fnはどんどん乱雑になります。それ、私の友人は、地獄への道です。

これは、魔法のボタンのアプローチを使用することの兆候です。周りのOOjsライブラリの多くを使用して、実際の継承ベースのクラスモデルに移行することを検討する必要があります。次に、$ base.fn()または$ super.fn()を呼び出すことができます。

于 2011-10-29T06:42:34.870 に答える
0

あなたの質問を理解できたら、特定のケースに合わせて機能を変更したいと考えています。これが事実で、オーバーヘッドが必要ない場合は、インスタンス化時にメソッドをオーバーライドすることに依存します。

モデルをオーバーライド

あなたのクラス:

dojo.declare("some.path.DrawingThing", [dijit._Widget], {
    draw: function () {
        this.inherited(arguments); // Call super class methods
        // override this method to do specialized things that're specific 
        // to an instance.
    }
});

クライアントのインスタンス化:

var drawer = new some.path.DrawingThing({
    draw: function () {
        beforeDraw();
        // Access the pre-existing functionality in a somewhat dirty way.
        this.constructor.prototype.draw.apply(this, arguments);
        afterDraw();
    }
});

このモデルに従えば、コードは少なくなりますが、きれいではありません。もう 1 つのオプションは、実際の API を作成することです。以下を参照してください。

イベントモデル

真の API が必要な場合は、イベントを提供します。

// Dojo 1.6 style declaration.
dojo.declare("some.path.DrawingThing", [dijit._Widget], {
    onBeforeDraw: function(){
        // Hook into this method to do something before draw
    },
    onDraw: function(){
        // Hook into this method to do something after draw
    },

    draw: function () {
        // This method is actually called when the draw even fires
        this.onBeforeDraw();
        this.inherited(arguments); // Call super class methods
        this.onDraw();
    }
});
于 2011-11-01T17:49:07.550 に答える