プラグインがプログラムフローに反応できるようにするアプリを考えてみましょう。
私はこれを達成する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);
}
);
_
[〜#〜]質問[〜#〜]
そのようなプラグインの動作を実装する他の主流の方法はありますか?
そうでない場合、いつフックを使用する必要があり、いつイベントを使用する必要がありますか?最終的な目標を検討することは、アプリとプラグイン開発者の両方の観点から、コードをより保守可能で読みやすくすることです
フックとイベントの主な違いは、疎結合と密結合です。
フックは、何かが起こったことをブロードキャストする一般的な方法です。プラグインを再コンパイルせずに新しいフックを追加でき、すべてのフックは一般的な設計パターンに従います。フックAPIが定義されると変更されないため、アプリとプラグインの間の結合が壊れる可能性はほとんどありません。
イベントはアプリとより密接に結びついています。イベントでは、イベントに添付されるパラメーターを定義できます。これらのパラメーターを変更すると、既存のプラグインでAPIが壊れます。
どちらも同じ結果になります。プラグインをアプリにどのように結合するかによって異なります。
フックは、アプリの新しいバージョンがリリースされても壊れない可能性が高い動的な結合を提供できますが、欠点は、プラグインに互換性がないというコンパイル時の警告が表示されないことです。
イベントは、一部のイベントシグネチャが変更されているため、プラグインを変更する必要があるコンパイル時エラーを取得する機能を提供します。
あなたは別のアプローチを求めました。
コマンド:
トリガーされたイベントに応答するプラグインの代わり。プラグインコマンドオブジェクトをアプリケーションにプッシュします。各コマンドオブジェクトは、コマンドで使用されるインターフェイスを実装します。アプリケーションが機能を実行する必要がある場合、その機能のすべてのコマンドを実行します。これは、コールバック関数の代わりにオブジェクトとして実装されることを除いて、イベントに非常に似ています。
マクロ:
物事が発生したときにプラグインが応答する代わりに。プラグインはプロアクティブに事態を発生させます。マクロは、アプリケーションの上で実行される小さな高級言語で、何をすべきかを伝えます。
状態変更リスナー:
イベントは、開発者による先見の明のあるアプリケーションによってトリガーされます。開発者は、イベントを発行するコードを故意に書く必要があります。代わりに、オブジェクトの内部状態が変化したときに、オブジェクトが自動的にブロードキャストするようにする方法もあります。プロパティまたはその他のインジケーターの変更。プラグインはこれらの特定の状態変化をリッスンし、それに応じて対応できます。このアプローチの利点は、プログラマがイベントをブロードキャストすることを覚えておく必要がないことです。たとえば、Documentオブジェクトがあり、プログラマがフラグを設定して、ドキュメントを保存する必要があることをマークします。この状態の変更はリスニングプラグインにブロードキャストされ、アスタリスクを含むようにドキュメントのタイトルを変更するプラグインが存在する可能性があります。
間違いなくイベントであり、すでに建築レベルで必要な抽象化を可能にします。
プラグインを書いている人が実際に文書化されている、または何らかの方法で正しいとは思わないでください。私は何百万ものユーザーで十分に文書化されたAPIを維持してきましたが、基本的に誰もドキュメントを読んだことがなく、ほとんど誰もAPIを正しく使用していないという非常に辛い経験からあなたに伝えることができます。
フックを使用した次の例を見てください。20個のプラグインが実行されているシステムがあります。これらのプラグインの1つは、文書化されている方法でfile_copy
メソッドを呼び出し、文書化されているとおりの結果を期待します。ただし、他の一部のプラグインがその機能をフックしているため、次の問題のいずれかがクラッシュまたは誤動作の原因になります。
これらのプラグイン内で同じ問題のあるイベントで上記と同じことを行うと、次のようになります。
継承はオプションの場合があります。
フック以外に、継承は追加のメソッド定義を必要とせず、何も接続されていない場合に空のメソッドを呼び出してもパフォーマンスが低下することはありません。
イベント以外に、継承にはイベント呼び出しのための追加のコードも必要ありません。
ただし、1つのタイプの動作を変更するプラグインが1つしかない場合は、継承が最適に機能します。多くのプラグインが必要な場合、2番目のプラグインは最初のプラグインから派生する必要があるなど、これは適切ではありません。
間違いなくイベント。それはあなたのアーキテクチャをより広いスケーラブルにすることを可能にします。
たとえば、プラグインを別のマシンに配置する必要がある場合にどうなるか想像してみてください。イベントの使用-イベントをネットワークベースにするために、コードの小さなピースを変更する必要があるだけです。