オブジェクト指向プログラミング(OOP)のイベントは、特定の条件が満たされたときに実行可能コードのさまざまなポイントで発生するメッセージです。 これらのメッセージはプロセッサ(リスナー)に送信されるため、システムの変更された状態にタイムリーに応答できます。
イベント指向プログラミングは非常に人気があります。 このプログラミングパラダイムでは、プログラムの実行はイベント(ユーザーアクション(キーボード、マウス)、他のプログラムおよびスレッドからのメッセージ、オペレーティングシステムイベントなど)によって決定されると述べています。
イベントモデルの利点と用途は非常に広範囲です。
- オブジェクトをイベントでバインドする場合、オブジェクトはお互いを「知る」必要はありません。
- このメカニズムは、OOPの概念に明確に適合しています。
- このメカニズムにより、各ユーザーアクションがイベントであるユーザーインターフェイスを簡単に実装できます。これらのイベントのハンドラーを「フック」するだけで十分です。
- サーバーアプリケーションを実装する場合、イベントモデルを使用すると、多数の処理プロセスの生成を取り除くことができます。
- イベントモデルは、多くのオブジェクトが制御されるゲームをプログラミングするときにもよく使用されます。
イベント処理に何らかの形で関連する設計パターンがあります:オブザーバー、チーム、責任チェーン、その他多数。 これらのパターンは、多くのイベント処理モデルで使用されます。 ただし、イベントモデルのさまざまな実装は、プログラムの開発の可能性にいくつかの制限を課します。
- イベントを処理するとき、メインハンドラーを選択することはできません。すべてのハンドラーは同じです。
- イベントを処理するとき、ハンドラーはお互いについても現在の状況についても何も知らないため、プログラマーが意図した機能を完全に実装することはできません。
- 結果のハンドラーを選択する場合は、追加の機能を追加する必要があります。
リストされた制限のリストは完全ではありませんが、指定された制限が最も重要です。 この記事では、これらの制限をすべて取り除く、より複雑なイベントモデルの実装を提案します。
このイベント処理モデルを使用してソフトウェアを開発する場合、処理ステップのシーケンスは次のとおりです。
- 必要なリスナーは、イベントを処理するために接続されています。
- プログラムコードでは、イベントがトリガーされます。
- 「第1ラウンド」の処理が実行され、このイベントの処理に接続しているすべてのリスナーにプライマリ処理の時間が与えられ、各リスナーは自分のデータ、イベントのイニシエーターからのデータを受信し、「第2ラウンド」に送信するデータを設定できます。 「第2ラウンド」のイベント処理に適用されます。
- このイベントのすべてのリスナーの中から、処理の優先度が最も高いアプリケーションを選択するリスナーが選択されます。「第2ラウンド」でイベントを処理する権利を与えられるのは彼です。 この処理の過程で、彼はイニシエーターからのデータ、彼自身のデータ、彼自身の「最初のラウンド」のハンドラーからのデータを受信できます。 処理が完了すると、イベントイニシエーターにデータを直接返すことができます。
このモデルの利点を考慮してください。
- 同じハンドラーを異なるイベントまたは同じものでさえ「ハング」させることができますが、異なるデータを使用します。
- 最も広範囲のイベントを処理することが可能です。 たとえば、新しいユーザーの追加、Webサイトページのデザインの表示など。 この場合、新しいユーザーを追加するイベントは「最初の円」のみを使用して処理でき、サイトページデザインの出力のイベントは「2つの円」で処理する必要があります。
- 「2番目のサークル」ハンドラーは1つだけ実行されます(サイトデザインの出力イベントを考慮してください:システムの状態を分析する最初のサークルでは、プロセッサーがイベントの処理を優先し、「2番目のサークル」でのみサイトページデザインを生成します)。
写真は、このモデルの実装スキームを示しています。 この実装は、最初は呼び出しチェーンを使用した作業に依存しています。 以下は、PHPでのモデルの実装例です。
- イベントはメインクラスです。 ユーザーが作成できるのはそのオブジェクトのみです。 このクラスは、イベントをトリガーし、イベントハンドラーを「フック」する機能を提供します。
- newListener-新しいリスナーを追加し、すぐに「構成」することができます(追加は、Events_Listener-Events_Listener_adapterSETのアダプターを介して行われます)。
- newEvent-新しいイベントを構成してからトリガーできます(このアクションは、Events_Fire-Events_Fire_adapterSETのアダプターを介して発生します)。
他のクラスはユーザープロセスに透過的に接続されています。
- Events_Fire-アダプターが制限する一般的なイベント処理インターフェースを提供します。
- Events_Fire1-処理の最初のラウンドが呼び出されたとき。 このクラスを使用すると、現在の状態の利用可能なすべてのデータを取得し、2番目のサークルハンドラーを追加し、その優先順位を設定することもできます(Events_Fire2_adapterSETアダプターを使用)。
- Events_Fire2-結果のハンドラーを呼び出すとき(「第2ラウンド」)。 このクラスを使用すると、「最初のラウンド」ハンドラーからのデータを含む、使用可能なすべてのデータを取得できます。
- Events_Listener-イベントハンドラを操作するための共通インターフェースを提供します。 このクラスのメソッドは、Events_Fire1、Events_Fire2というアダプターも使用します。
- Events_Data-イベントモデル内でデータを保存および送信するためのクラス。
このモデルの例を考えてみましょう。
class SampleListener { public function Fire1(Event_fire1 $EF1) { $EF1->setFinal(Array($this,”Fire2”), $EF1->getListenerData()->sort); } public function Fire2(Event_fire2 $EF2) { return ($EF2->getListenerData()->sort() + $EF2->getFireData()->sort()); } } $listener = new SampleListener(); $data1 = new Events_Data(); $data1->sort = 10; Events::newListener("sampleModul", "sampleEvent", Array($listener, 'Fire1'))->setData($data1); $data2 = new Events_Data(); $data2->sort = 20; Events::newListener("sampleModul", "sampleEvent", Array($listener, 'Fire1'))->setData($data2); $data3 = new Events_Data(); $data3->sort = 30; Echo Events::newEvent("sampleModul", "sampleEvent")->setData($data3)->fire();
sampleEventイベントが
トリガーされた後、$リスナーのFire1メソッドが最初のデータで
呼び出され
(sort = 10、最終処理にこの優先順位が付けられます) 、次に同じメソッドが他のデータで呼び出されます
(sort = 20、20
> 10、したがってリスナーこのデータは、イベントの最終処理の権利を受け取ります) 。 結論として、Fire2メソッドが
呼び出されます (ハンドラーは同じですが、データは$ data2です) 。 イベント
(sort = 30)からのデータは、リスナー
(sort = 20)からのデータに追加されます。 その結果、返されるイベントは数値50を返し、画面に表示されます。
この例は、同じハンドラーがリスナーのデータに応じてイベントに異なる応答をすることができることを示しています。 また、
Fire2への単一の呼び出しを含むイベントの処理プロセスを示します
(たとえば、サイトのページデザインが生成され、データがイベント処理の外部コンテキストであるなど、このメソッド内にあると想像してください) 。
このイベント処理モデルを実装することにより、上記の制限をすべて取り除くことができました。 現在、モデルは特定の製品に焦点を合わせています(この製品にのみ必要な寄生的な方法があります)が、興味がある場合は、パブリックバージョンのコードを準備できます。
このモデルを他のプログラミング言語で実装することもできます。 cppでは、ポインターをデータとして渡し、処理メソッドでreinterpret_castを使用するか、テンプレートを使用できます。
特定の状況ごとの実装はわずかに異なる場合がありますが、主なポイントは、2つ以上のレベルの実装にあります。