「通知センター」パターンは、プログラム設計の良し悪しを促進しますか?


13

Cocoa NSNotificationCenterなど、これらのメッセージハブスタイルのAPIに出くわすことがあります。http//developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/Reference/Reference.html

通常、これらのAPIは、メッセージ/イベントをサブスクライブまたはブロードキャストするグローバルアクセスポイントを提供します。これは、依存関係がAPIで明示されていないがソースコードに隠されているフラットで非構造化のプログラムアーキテクチャを促進するため、これが問題だと考えています。オブジェクトの所有権と階層について考える必要はありませんが、プログラム内の任意のオブジェクトを呼び出すことで、任意のコードを呼び出すことができます。しかし、これは良いことでしょうか?

このパターンは一般に、プログラム設計の良し悪しを助長しますか?コードをテストするのが難しくなりますか、それとも簡単になりますか?

この質問が曖昧すぎるか広すぎる場合はご容赦ください。私は、このようなAPIの広範な使用の潜在的な結果と、それを使用できるさまざまな方法について頭をかき回しています。

編集:このパターンの最大の問題は、APIが依存関係とオブジェクトカップリングについて「嘘をつく」ことであり、この例で説明できることです。

myObj = new Foo();
myOtherObj = new Bar();
print myOtherObj.someValue; // prints 0
myObj.doSomething();
print myOtherObj.someValue; // prints 1, unexpectedly, because I never indicated that these objects had anything to do with each other

この例に具体的に疑問を投げかけていますか、それとも一般的なリスナーパターンですか?
TheLQ

これはリスナーのパターンよりも広いと思います。リスナーパターンは、明確に定義されたオブジェクト構造と特定のオブジェクトにリスナーを登録することで「きれいに」実装できます。私の不確実性は、グローバルなメッセージ/イベントハブパターンに関するものです。
マグナスウルフフェルト

回答:


6

悪いプログラミングを助長すると言っている限り、私は行きません。しかし、簡単に悪用される可能性があります。

さて、実際のアイデアは何ですか?
通知のソースは通知のみを行います。潜在的なオブザーバーなどの存在については想定していません。オブザーバーは、処理するように設計された通知を登録します。オブザーバは、処理する可能性のある通知に対して潜在的なソースがいくつあるかについて、何も仮定しません。

これは、ソースがオブザーバーを知らない、またはオブザーバーがソースを知ることなく、依存性注入を実現する方法です。ただし、システム全体が機能するためには、正しい通知のために正しいオブザーバーを接続する必要があります。このシステムはコンパイル時にチェックできないため、タイプミスに対しても脆弱です。

もちろん最大の危険は、誰かがこれを使用して、1対1の呼び出しで大量のオブジェクトをグローバルに利用可能にすることです。


6

非同期メッセージングは​​、拡張が必要な​​大規模システムの優れたアーキテクチャプリンシパルです

これに相当するJavaはJMSであり、一般に良いことと考えられています。

これは、実際にメッセージを処理するコードからクライアントコードの分離を促進するためです。クライアントコードは、単にメッセージの送信先を知っている必要があります。サービスコードは、メッセージをピックアップする場所を知っている必要があります。クライアントとサービスは互いに何も知らないため、必要に応じて互いに独立して変更できます。

メッセージハブのURIを簡単に外部化して、ソースコードに埋め込まずに構成可能にすることができます。


4

これは、典型的なOberserverパターンの実装です(または、リスナーパターンまたはサブスクライバー/パブリッシャーパターンと呼ばれることもあります)。これが動作に役立つアプリケーションでは、実装するのに適したパターンです。ソリューションに値を追加しない場合、パターンを実装しないでください。

あなたの質問から、すべてがNotificationCenterについて知っていること、そしてグローバルなものが悪いことを心配しているように聞こえます。時には、はい、グローバルなものは悪いです。しかし、代替案を見てみましょう。2つのコンポーネントがあるとしましょう。この例では、実際に何をするか、何をするかは重要ではありません。Component1には、何らかの方法で処理または変更されたデータが含まれています。Component2は、Compoent1が管理するタイプのデータの変更について知りたいと考えています。Component2はComponent1の存在を知る必要がありますか?または、Component2がアプリ内のどこかのコンポーネントが興味のあるデータを変更したことを伝えるメッセージをサブスクライブ/リッスンする方が良いでしょうか?次に、この例を取り上げて、数十個以上のコンポーネントを掛けると、パターンの値がどこにあるかがわかります。

それはあらゆる状況に最適なソリューションですか?コンポーネント間の通信を抽象化し、より疎結合を提供しますか、はい。


1
ウィキペディアを読むと、オブザーバーパターン定義には、グローバルに利用可能なイベントハブが含まれていないようです。イベントハブが関連するすべてのオブジェクトのコンストラクター/メソッドに渡された場合、これは良いパターンだと思います。確かに、グローバルアクセスポイントとその状態が私を不確かにします。
マグナスウルフフェルト

0

これは、イベント駆動型システムに適しています。また、イベントを起動するオブザーバーの不注意な無限ループが発生する可能性が低いため、多数のオブザーバーがお互いを監視するという選択肢よりも優れています。これは、イベントハンドラーを使用して相互に接続できるイベント駆動型ActiveXコントロールがあった古いVB時代に本当の問題でした。

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