web-dev-qa-db-ja.com

プラグインは何を使用する必要がありますか:フック、イベントなど

プラグインがプログラムフローに反応できるようにするアプリを考えてみましょう。

私はこれを達成する2つの方法を知っています:hooksおよびevents

1。フック

メインプログラムフロー内の関数を空にする呼び出しを使用します。これらの関数はプラグインによってオーバーライドできます。

たとえば、Drupal CMSは、モジュールおよびテーマで使用できるフックを実装します。フックが file_copy 関数で実装される方法の例を次に示します。

_function file_copy(stdClass $source, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
    // ... [File copying routine]

    // Inform modules that the file has been copied.
    module_invoke_all('file_copy', $file, $source);

    return $file;
    // ...
}
_

モジュールは、_module_invoke_all_の_file_copy_によって呼び出されるmodulename_file_copy($file, $source)関数を実装できます。この関数が終了すると、_file_copy_が実行を再開します。

2。イベント

プラグインでリッスンできるアプリディスパッチイベントを用意します。プラグインは、サブスクライブされているイベントを受信した後、プログラムフローをインターセプトし、必要な操作を実行します。

たとえば、jQueryギャラリープラグインFotorama いくつかのイベントを実装 。例として、_fotorama:show_イベントを発生させるshowメソッドの一部を次に示します。

_  that.show = function (options) {
    // ... [show the new frame]

    // [fire the event]
    options.reset || triggerEvent('show', {
      user: options.user,
      time: time
    });

    // ... [do lots of other stuff with navigation bars, etc.]
  };
_

スクリプトはこのイベントをリッスンして、起動時に何かを実行できます。

_$('.fotorama').on(
  'fotorama:show',
  function (e, fotorama, extra) {
    console.log(e.type + (extra.user ? ' after user’s touch' : ''));
    console.log('transition duration: ' + extra.time);
  }
);
_

[〜#〜]質問[〜#〜]

  1. そのようなプラグインの動作を実装する他の主流の方法はありますか?

  2. そうでない場合、いつフックを使用する必要があり、いつイベントを使用する必要がありますか?最終的な目標を検討することは、アプリとプラグイン開発者の両方の観点から、コードをより保守可能で読みやすくすることです

24
sbichenko

フックとイベントの主な違いは、疎結合と密結合です。

フックは、何かが起こったことをブロードキャストする一般的な方法です。プラグインを再コンパイルせずに新しいフックを追加でき、すべてのフックは一般的な設計パターンに従います。フックAPIが定義されると変更されないため、アプリとプラグインの間の結合が壊れる可能性はほとんどありません。

イベントはアプリとより密接に結びついています。イベントでは、イベントに添付されるパラメーターを定義できます。これらのパラメーターを変更すると、既存のプラグインでAPIが壊れます。

どちらも同じ結果になります。プラグインをアプリにどのように結合するかによって異なります。

フックは、アプリの新しいバージョンがリリースされても壊れない可能性が高い動的な結合を提供できますが、欠点は、プラグインに互換性がないというコンパイル時の警告が表示されないことです。

イベントは、一部のイベントシグネチャが変更されているため、プラグインを変更する必要があるコンパイル時エラーを取得する機能を提供します。

あなたは別のアプローチを求めました。

コマンド:

トリガーされたイベントに応答するプラグインの代わり。プラグインコマンドオブジェクトをアプリケーションにプッシュします。各コマンドオブジェクトは、コマンドで使用されるインターフェイスを実装します。アプリケーションが機能を実行する必要がある場合、その機能のすべてのコマンドを実行します。これは、コールバック関数の代わりにオブジェクトとして実装されることを除いて、イベントに非常に似ています。

マクロ:

物事が発生したときにプラグインが応答する代わりに。プラグインはプロアクティブに事態を発生させます。マクロは、アプリケーションの上で実行される小さな高級言語で、何をすべきかを伝えます。

状態変更リスナー:

イベントは、開発者による先見の明のあるアプリケーションによってトリガーされます。開発者は、イベントを発行するコードを故意に書く必要があります。代わりに、オブジェクトの内部状態が変化したときに、オブジェクトが自動的にブロードキャストするようにする方法もあります。プロパティまたはその他のインジケーターの変更。プラグインはこれらの特定の状態変化をリッスンし、それに応じて対応できます。このアプローチの利点は、プログラマがイベントをブロードキャストすることを覚えておく必要がないことです。たとえば、Documentオブジェクトがあり、プログラマがフラグを設定して、ドキュメントを保存する必要があることをマークします。この状態の変更はリスニングプラグインにブロードキャストされ、アスタリスクを含むようにドキュメントのタイトルを変更するプラグインが存在する可能性があります。

17
Reactgular

間違いなくイベントであり、すでに建築レベルで必要な抽象化を可能にします。

プラグインを書いている人が実際に文書化されている、または何らかの方法で正しいとは思わないでください。私は何百万ものユーザーで十分に文書化されたAPIを維持してきましたが、基本的に誰もドキュメントを読んだことがなく、ほとんど誰もAPIを正しく使用していないという非常に辛い経験からあなたに伝えることができます。

フックを使用した次の例を見てください。20個のプラグインが実行されているシステムがあります。これらのプラグインの1つは、文書化されている方法でfile_copyメソッドを呼び出し、文書化されているとおりの結果を期待します。ただし、他の一部のプラグインがその機能をフックしているため、次の問題のいずれかがクラッシュまたは誤動作の原因になります。

  • フック関数は単にクラッシュします。他のすべてのプラグインは、file_copyを実行できなくなったり、関数が予期したものとは異なる動作をしたりするため、今ではねじ込まれています。
  • ドキュメントに基づいて入力は正しいですが、他のプラグインはそれを予期せず、奇妙な結果またはクラッシュを提供します。
  • 呼び出しは問題なく実行されますが、ドキュメントによると、結果は期待どおりではなくなったため、プラグインが失敗またはクラッシュします。

これらのプラグイン内で同じ問題のあるイベントで上記と同じことを行うと、次のようになります。

  • プラグインXのイベント機能はクラッシュしますが、他のすべては正常に動作します。ただし、これらのプラグインは関連していないため、他のプラグインが引き続き正常に機能している間に、クラッシュするプラグインを無効にすることができます。
  • 奇妙な入力を関数で適切に処理でき、各プラグインで可能なすべてのことを個別に適切にチェックできます。プラグイン開発者は、プラグインを実際にテストするための安定した信頼できる方法を手に入れました。これにより、プラグインが機能すれば、誰にとっても機能することを確認できます。 1つのプラグインが誤った入力を提供する場合、その1つのプラグインに分離できます。
  • 同様に、すべての状況下で結果を適切にチェックおよび定義できるため、プラグイン開発者は、テストできるその機能から安定した信頼できる回答を得られます。
3
TwoThe

継承はオプションの場合があります。

フック以外に、継承は追加のメソッド定義を必要とせず、何も接続されていない場合に空のメソッドを呼び出してもパフォーマンスが低下することはありません。

イベント以外に、継承にはイベント呼び出しのための追加のコードも必要ありません。

ただし、1つのタイプの動作を変更するプラグインが1つしかない場合は、継承が最適に機能します。多くのプラグインが必要な場合、2番目のプラグインは最初のプラグインから派生する必要があるなど、これは適切ではありません。

1
Thomas Weller

間違いなくイベント。それはあなたのアーキテクチャをより広いスケーラブルにすることを可能にします。

たとえば、プラグインを別のマシンに配置する必要がある場合にどうなるか想像してみてください。イベントの使用-イベントをネットワークベースにするために、コードの小さなピースを変更する必要があるだけです。

0
vpol