序文の代わりに
デザインパターン専用のGang of Fourの伝説的な本がリリースされてから17年が経ちました。 このような堅実な期間にもかかわらず、そこに記載されている方法の関連性に挑戦することは困難です。 デザインパターンは生き続け、進化します。 それらは使用され、議論され、scられ、賞賛されます。 残念ながら、多くの人にとって、それらは依然として不必要な抽象化のままです。
人生とさまざまなリソースの両方で同僚とさまざまなプログラミングの問題を議論するとき、特定のパターンの重要性を説明することがしばしば必要です。 そのため、具体的な例を使用して、プログラマーの生活をどれだけ楽にできるかを示すためにアイデアが生まれました。 iOSのようなプラットフォームに関してもです。
オブザーバーパターン
人生の例
学生Vasyaはパーティーに行くのが大好きです。 もっと正確に言うと、彼らは彼が人生の重要な部分を占めていたので、彼は研究所から追放されました。 仕事を探し始めたヴァシャは、自分がほとんど何も知らず、できなかったことに気付きました。 しかし、待ってください... Vasyaにはパンを食べない美しい少女がたくさんいます-彼らを招待なしでクールなパーティーに参加させてください。 Vasyaは、彼の都市のすべての関連機関でも知られています。 最後に、Vasyaは次のことを理解しています。パーティーが成功する(裕福な訪問者が多額のお金を費やした)ために、美しい女の子(このお金を使う人)で満たすのは良いことです。
それで、ヴァシャ
1年が経ち、スヴェタは研究所を卒業し、仕事を見つけ、そして最も重要なことに、結婚しました! 彼女はもはやパーティーに行きたくないので、昨日彼女はヴァシャに電話し、彼女のばかげたメッセージで彼女をもう困らせないように頼んだ。 そのため、彼女は Vasyaの(非常に疑わしい) 件名から退会しました。 しかし、彼女はいつでもサインアップできることを知っています(彼女はまだきれいで、若く、格好いいです)。
一方、Vasyaは静止していませんでしたが、事業を拡大しました。 最近、彼はパーティーでリラックスするのが好きで、ノンアルコールカクテルでかわいい女の子を扱う準備ができている非常に裕福なサッカー選手に会いました。 当然、彼らはさまざまなイベントに招待することもできます(主催者は喜んで、Vasyaにもっとお金を払います)。 事業拡大は見過ごされていました。実際、誰が誰に電話するか気にしますか? 女の子もサッカー選手も電話を持っています。 時々、Vasyaは新しいイベントを報告して、自分が話している相手を混乱させることさえあります。
より短い例
Vasyaのビジネスに密接に従った人は、すぐにニュースレターを思い出すことができました。 確かに、私たちはあなたのメールアドレスをお気に入りのリソースに残し、対応するウェブページに毎日アクセスしなくても、重要で興味深いニュースを
定義
ギャングオブフォー
- タイトル: オブザーバー。
- 分類:行動パターン。
- 予定:
1つのオブジェクトの状態が変化すると、そのオブジェクトに依存するすべてのオブジェクトに通知され、自動的に更新されるように、オブジェクト間の1対多の関係を定義します。
コメント
そのため、オブザーバーパターンは1対多の関係を定義します。 さらに、変更について報告するオブジェクトはサブジェクトと呼ばれ、変更について報告するオブジェクトはobserversと呼ばれます。
観察者パターンの重要な特徴に注目する価値があります。被験者は観察者についてほとんど何も知らないかもしれません。 そのため、ヴァシャは女の子と選手の間に違いは見ませんでした。
構造

iOS開発者向けオブザーバー
プログラミングに移りましょう。 最初に、特定の例を使用してオブザーバーパターンの独自の実装を分析し、次にCocoaで実装された通知メカニズムを分析します。
独自の実装
App Storeを爆破する完全に新しいゲームを開発しているとしましょう。 次のレベルを通過した後、次の2つのことを行う必要があります。
- お祝い画面を表示します。
- 新しいレベルへのオープンアクセス。
最初のアクションと2番目のアクションは互いに関連していないことに注意してください。 ランダムな順序で実行できます。 また、近い将来、そのようなアクションの数を増やす必要があると思われます(たとえば、サーバーにデータを送信したり、ユーザーがGame Centerで実績を獲得したかどうかを確認したりする)。
調査したオブザーバーパターンを適用します。 オブザーバープロトコルから始めましょう。
@protocol GameStateObserver <NSObject>
- ( void ) completedLevel : ( Level * ) level withScore : ( NSUInteger )スコア。
@end
ここではすべてが透明です。オブザーバーは
GameStateObserver
プロトコルを実装します。 私たちはこの問題に対処します。
@protocol GameStateSubject <NSObject>
- ( void ) addObserver : ( id <GameStateObserver> )オブザーバー;
- ( void ) removeObserver : ( id <GameStateObserver> )オブザーバー;
- ( void ) notifyObservers;
@end
興味のあるクラスに移りましょう。 現在のゲームの状態を
GameState
クラスのオブジェクトに保存します。 次に、その定義は次のようになります。
@interface GameState : NSObject <GameStateSubject> {
...
NSMutableSet * observerCollection;
}
@property ( readonly )レベル*レベル。
@property ( readonly ) NSUIntegerスコア。
...
- ( void ) updateState;
@end
同時に、ゲームに大きな変更が発生するたびに
updateState
メソッド
updateState
呼び出されると考えてい
updateState
。
GameState
実装の一部を次に示します。
@implementation GameState
...
- ( void ) addObserver : ( id <GameStateObserver> )オブザーバー{
[ observerCollection addObject : observer ] ;
}
- ( void ) removeObserver : ( id <GameStateObserver> )オブザーバー{
[ observerCollection removeObject : observer ] ;
}
- ( void ) notifyObservers {
for ( id <GameStateObserver> observerCollectionのオブザーバー) {
[オブザーバーcompletedLevel : self.level withScore : self.score ] ;
}
}
- ( void ) updateState {
...
if ( levelCompleted ) {
[ self notifyObservers ] ;
}
}
@end
これで、レベルの正常な完了を知る必要があるオブジェクトについては、
GameStateObserver
プロトコルを実装し、正常な完了の通知をサブスクライブするだけで十分です。 適切なコードは次のようになります。
GameState * gameState = [ [ GameState alloc ] init ] ;
[ gameState addObserver : levelManager ] ;
[ gameState addObserver : levelViewController ] ;
ここで、
levelViewController
はゲームプロセスのインターフェイスを担当するコントローラーであり、
levelManager
はレベルに応答するモデルオブジェクトです。
議論
かなり原始的な例を調べましたが、それはどこにでもあります。 ソリューションが非常に柔軟であることはすぐに明らかです。 通知では、一部のデータをパラメーターとして転送することに決定したことに注意してください。 このような実装には長所と短所があります。
GameStateObserver
プロトコルの次のバージョンを使用すると便利な場合があります。
@protocol GameStateObserver <NSObject>
- ( void ) levelCompleted : ( id <GameStateSubject> )件名;
@end
GameStateSubject
の対応するバリアントは次のようになります。
@protocol GameStateSubject <NSObject>
- ( void ) addObserver : ( id <GameStateObserver> )オブザーバー;
- ( void ) removeObserver : ( id <GameStateObserver> )オブザーバー;
- ( void ) notifyObservers;
@property ( readonly )レベル*レベル。
@property ( readonly ) NSUIntegerスコア。
@end
Cocoaのオブザーバー:通知
Cocoaには、オブザーバーパターンを実装するメカニズムがあることがわかります。 完全に正確に言うと、このようなメカニズムが2つあります。 現時点では、通知メカニズムに焦点を当て、2つ目は将来のために残します。 さらに、すべての微妙な点については説明しませんが、基本的な機能のみを説明します。
非公式には、通知メカニズムにより、通知のサブスクライブ/サブスクライブ解除、およびすべてのサブスクライバーへの通知の送信という2つのことができます。 アラートは
NSNotification
クラスのインスタンスです。 アラートは
name
タイプ
NSString
文字列名
name
によって設定されます。 名前に加えて、アラートにはサブジェクトエンティティと
NSDictionary
タイプの追加の
userInfo
データも含まれます。
NSNotificationCenter
は、アラートのサブスクライブと配信を担当します。 ほとんどの場合、それにアクセスするには、
defaultCenter
クラスメソッドを呼び出します。
メッセージをサブスクライブするために、通知センターには
addObserver:selector:name:object:
メソッドがあります。 最初のパラメーターはオブザーバーであり、2番目はセレクターであり、通知時に呼び出されます。 署名
- (void)methodName:(NSNotification *)
です。 3番目のパラメーターはアラートの名前、4番目はサブジェクトです。 件名として
nil
を渡すと、任意の送信者から通知が配信されます(名前が一致する場合)。 アラートを使用すると、サブスクリプションコードは次のようになります。
GameState * gameState = [ [ GameState alloc ] init ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : levelManager
セレクター: @selector ( levelCompleted :)
名前: @ "LevelCompletedNotification"オブジェクト: gameState ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : levelViewController
セレクター: @selector ( levelCompleted :)
名前: @ "LevelCompletedNotification"オブジェクト: gameState ] ;
levelCompleted:
メソッドの例
levelCompleted:
- ( void ) levelCompleted : ( NSNotification * )通知{
id <GameStateSubject> subject = [通知オブジェクト] ;
レベル*レベル= subject.level;
NSUIntegerスコア= subject.score;
}
一般的に、
GameStateSubject
プロトコルを
GameState
直接使用できます。
アラートの登録を解除するには、
removeObserver:
または
removeObserver:name:object:
メソッドのいずれかを呼び出す必要があります。
アラートの送信はさらに簡単なプロセスです。 そのために、メソッド
postNotificationName:object:
および
postNotificationName:object:userInfo:
ます。 最初は
userInfo
nil
設定します。
notifyObservers
メソッドの新しい実装は次のとおりです。
- ( void ) notifyObservers {
[ [ NSNotificationCenter defaultCenter ]
postNotificationName : @ "LevelCompletedNotification"オブジェクト: self ] ;
}
コメント
アラートを送信するメカニズムは、説明した以上のことができます。 たとえば、上記のコードはすべて同期的です。 アラートを非同期的に送信するには、
NSNotificationQueue
アラート
NSNotificationQueue
使用する必要があり
NSNotificationQueue
。
また、説明したすべてがCocoaとCocoa Touchの両方で機能することにも注意してください。 将来的には、iOSプラットフォームの一部の機能を引き続き使用します。
あとがきの代わりに
私たちが検討し、学んだことを要約しましょう。 だから私たち:
- オブザーバーの設計パターンを研究しました。
- 頻繁に遭遇する状況で彼自身の実装を使用しました。
- Cocoaの通知エンジンで同じことを行うことを学びました。
- 設計パターンは怖くなく、複雑でも面倒でもないことを学びました。
- パターンは天井からではなく、実生活から取られていることに気付きました( プロモーター Vasyaの
ヒモを思い出してください)!
第2部では、オブザーバパターンも実装するKey-Value Observingメカニズムについて学習します。 これからさらに多くのパターンがあります!
有用なソース
- E.ガンマ、R。ヘルム、R。ジョンソン、J。ヴリスサイドオブジェクト指向デザインのレセプション。 デザインパターン:デザインパターン:再利用可能なオブジェクト指向ソフトウェアの要素。 -サンクトペテルブルク:ピーター、2007。-S.366。-ISBN 978-5-469-01136-1(ISBN 5-272-00355-1)
- E.フリーマン、E。フリーマン、C。シエラ、B。ベイツデザインパターン=ヘッドファーストデザインパターン-サンクトペテルブルク:ピーター、2011年-P.656。-ISBN 978-5-459-00435-9
- 通知プログラミングのトピック -iOS Developer Library