フックが適切なデザインの選択になるのはいつですか?


10

私はActiveRecordコールバックの使用が横行し、悲惨な大規模なRailsアプリに取り組んできました。多くの場合、レコードを保存すると予期しない副作用が発生し、システムについて推論することが困難でした。

同時に、継承の一部として有効に使用されるフック(たとえば、サブクラスが親の内部について知る必要なく特別な動作を追加できるようにするテンプレートメソッドを使用する親クラス)とプラグインを使用するフックを見てきました(例えば、emacsモードがアクティブになるとフックを実行し、ユーザーがそのモードの周りにカスタム動作を追加できるようにします)。

RailsアプリとLispインタープリターは非常に異なるシステムであることは理解していますが、直面している問題に対してフックが適切な設計の選択肢であるかどうかを決定するときに、よく知られている基準があるかどうか知りたいです。

私に飛びつくテーマは予測可能性です。フックの誤用は、遠くで不気味な行動や意外な振る舞いにつながるようですが、適切に使用すると、緊密な結合がなくても予測可能なフレームワークにつながる可能性があります。

私はまだプログラミングのキャリアを始めて数年しか経っていないので、私は多くの点で自分自身を初心者だと考えており、人々はこのトピックにかなりの量の考えを入れていると思われます。この決定を導くことができるいくつかのガイドラインは何ですか?

回答:


5

フックは、制御をフックのレシーバーに転送することにより、抽象化の実装の詳細をコンシューマーから切り離したい場合に適した設計の選択肢です。

匿名のブロードキャスト(イベントや匿名のコールバックなど)、または型付きの抽象化(インターフェイスや親クラスなど)を使用して行うことができます。

次の場合は匿名ブロードキャストを使用する必要があります。

  • フックの呼び出しはオプションです
  • 呼び出し元は、誰がフックに反応するかを気にしません。
  • レシーバーの実行順序は関係ありません。
  • オブジェクトの状態をフックのすべてのサブスクライバーにブロードキャストします。

次の場合は、型付き抽象化を使用する必要があります。

  • フックの呼び出しは必須です。
  • 呼び出し元のオブジェクトは、フックの受信者を識別する必要があります。
  • レシーバーの実行順序はオブジェクトに関連しています。

ブロードキャストフックの例はKeyPressedEventです。イベントを発生させるクラスは、誰がそれを受信するかを気にせず、イベントに登録している人にキーボードの状態をブロードキャストしています。レシーバーの実行順序は、イベントを発生させるクラスのオブジェクト状態には影響しません。

型付き抽象化フックの例は、あなたが言及したテンプレートメソッドです。この場合、親クラスはテンプレートメソッドの実装を必要とし、レシーバーがその子になることを認識しており、親クラスで定義されているように、テンプレートメソッドの特定の実行順序を持っています。


7

ほとんどの言語、およびほとんどのプラットフォームでは、他のものとしてドレスアップされていても、フッキングを使用します。「イベント」、「メッセージ」、「トリガー」、「シグナル」、またはそのような他の用語を耳にしたときはいつでも、おそらくフックに対処していますが、ルールには例外がありますが、この議論の問題。

それらは、プラットフォームが提供するため、または場合によってはパフォーマンス上の理由から使用が必要になるため、使用します。フックを使用すると、コードの複雑さが軽減され、ビジネス要件が適用され、CPU使用率が削減され、バッテリーとハードウェアの寿命が延びます。コードから最高のパフォーマンスを得たい場合はいつでも使用してください。

Railsの悲惨な経験でさえ、フックの一般的な使用例をほとんど特定できます。ビジネスルールを適用する必要があり、フックはビジネスルールを適用するために非常に広く使用されています。残念ながら、すべてのルールが意味をなすわけではなく、言うまでもないことですが、ルールが恣意的である場合、開発者にとって事態は難しくなりますが、システムのドキュメントはコード自体と同じくらい重要です。

原則として、フックはパフォーマンス機能であるため、フックを使用してください。これにより、コードは代替(ポーリングと呼ばれ、ビジーループでイベントを確認するために待機する)よりも効率的に実行されます。ただし、適切なドキュメントを使用し、最新の状態に保つことも確認してください。フックは、実際に遭遇するほとんどすべての言語で使用されています。フックが存在する理由を知ることは重要です。


1

私は以前、私の意見ではフックをうまく利用するプログラムに取り組んできました。私の本では、真のフックはコールバック(サブスクライバー)のリストへの呼び出し(発行)です。それは強力で、乱用は簡単です。使用例を尋ねるのに最適な質問は、実行時に動作を有効または無効にしますか?たとえば、特定のイベントで実行するスクリプトをユーザーが提供できるようにしたり、より小さなプラグインで作られた汎用プログラムを作成したりできます。次に、フック呼び出しが適切です。一般に、他のオプションはほとんどありません。

そうでない場合は、モジュールの優れたアーチで回避する必要があります。テンプレートメソッドはオーバーロードされた関数でうまく機能し、これのためのランタイムロジックは必要ありません。それが疎結合を強制することは幻想であると考えてください:直接呼び出すものとフックするものの間には同じ依存関係レベルがあり、呼び出し先はとにかくその契約を満たす必要があります。

オーバーロードされた関数をフックしてテンプレートメソッドを呼び出す人もいますが、これは上記とは異なります。静的リンクがあり、メンテナンスの悪夢に陥るリスクが低いことに注意してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.