Start Developing iOS Apps Today(sup.6)〜デザインパターンを使ったアプリの合理化

2012. 12. 24
Objective-Cプログラミングにおいて、アプリに固有の動作を追加する1つの方法は継承を介して行われます。
スーパークラスの属性や動作を増補するか、いくつかの方法でそれらを修正して、既存のクラスのサブクラスを生成します。
しかし他にもサブクラス化を伴わずに、アプリ固有の動作を追加するより動的な方法があります。
これらの動的な技術とアプローチはデザインパターンに基づいています。
この記事が説明するように、貴方のコードにデザインパターンを採用することで、貴方のクラスとフレームワークのクラスの両方に再利用性と拡張性を提供します。



●デザインパターン:プログラミングの問題を解決するためのデザインのテンプレート

デザインパターンはオブジェクト指向のソフトウェア開発だけでなく、他の分野でも使用される抽象化のツールです。
テンプレートは一般的に、特定の状況で繰り返し発生する問題を解決するための設計です。
デザインパターンは特定するためのガイドのようなもので、実際の設計はある意味でパターンの『インスタンス化』と言えます。
適用することができるデザインパターンは柔軟性があり、多くの場合プログラミング言語や既存のアーキテクチャなどによって適用されるパターンが決定されます。

いくつかの設計のテーマまたは原理はデザインパターンに影響を与えます。
これらの設計原理は、『変化するシステム構成のカプセル化』や『実装ではなく、インターフェイスへのプログラム』など、オブジェクト指向システムを構築するための経験則です。
これらは重要な洞察を表現しています。
例えばカプセル化の原則は変化するシステムの一部を分離したい場合、それらをカプセル化し、システムの他の部品から独立して変更することができるようにすることで、特に実装の仕様に縛られないインターフェイスを定義する場合に用いられます。
そうすることでシステムの他の部品に影響を及ぼすこと無く、それらの可変部品を後から変更または拡張することができます。
このように部品間の依存状態を排除し結合を減らすことによって、システムはより柔軟かつ変更を容易にすることができます。

このような利点は、ソフトウェアを記述する際にデザインパターンの重要な考慮事項です。
アプリの設計でパターンに気付く、あるいは適応させたり使用する場合、
将来に要件が要求された際、プログラム(および構成するオブジェクトやクラス)の再利用や拡張がより容易になります。
更に、デザインパターンに基づいたアプリは一般的にそうではないアプリよりも洗練され且つ効率的になり、同じ目的を果たすためのコード行数が少なくなります。

貴方はCocoa TouchとCocoaフレームワーク、およびObjective-Cのランタイムと言語の全般で、デザインパターンの適応を見つけることができるでしょう。
これらのパターンベースのメカニズムのいくつかはほとんど『無償で』取得できますが、他の貴方の部品は作業をする必要があります。
状態が保証されている場合、貴方の独自のアプリのコードにデザインパターンを適用することができます。
貴方がCocoa TouchやCocoaフレームワークが使用しているものと同じパターンを使用する場合、貴方のコードはフレームワークのコードとより良く適合し、より洗練された動作をする傾向があります。



●最も重要なデザインパターン:モデル-ビュー-コントローラ

(一般的にMVCとして知られる)モデル-ビュー-コントローラデザインパターンは、アプリのオブジェクトを(モデル、ビュー、コントローラの)3つの役割のいずれかに割り当てることです。
パターンはアプリ内でのオブジェクトが果たす役割を定義するだけでなく、オブジェクトが相互に通信する方法を定義します。
3つのタイプのオブジェクトそれぞれが抽象的な境界によって他から分離し、それらの境界を越えて他のタイプのオブジェクトと通信します。
アプリ内のMVCタイプのオブジェクトのコレクションは、時々(モデル層など)層と呼ばれます。

model_view_controller_2x.png

MVCは全てのiOSアプリやMacアプリのための優れた設計の中心となるものです。
このパターンを採用することの利益はたくさんあります。
これらのアプリでは多くのオブジェクトが再利用し易くなる傾向があり、そしてインターフェイスがより良く定義される傾向があります。
MVCデザインを持つアプリは、他のアプリよりも容易に拡張することができます。
更に、貴方のアプリが使用することができる多くの技術やアーキテクチャはMVCに基づいており、カスタムオブジェクトはMVCの役割のいずれかを果たす必要があります。

貴方は気付いていないかもしれませんが、『初めてのiOSアプリケーション』のHelloWorldで貴方は既にMVCに基づいたアプリを生成しています。
モデルオブジェクトはuserNameプロパティ(NSStringオブジェクト)が宣言され、HelloWorldViewControllerクラスによって管理されます。
HelloWorldViewControllerとHelloWorldAppDelegateクラスのインスタンスはアプリのコントローラオブジェクトで、アプリのビューオブジェクトはテキストフィールド、ラベル、ボタン、そして背景のビューになります。

モデル-ビュー-コントローラについての詳細は、『Objective-Cプログラミングの概念』の『Model-View-Controllerパターン』を参照してください。


モデルオブジェクト

モデルオブジェクトはアプリのデータをカプセル化し、データの操作や処理の計算とロジックを定義します。
例えばモデルオブジェクトは、ゲーム内の文字やアドレス帳の連絡先を表すことがあります。
時々、アプリのモデル層は事実上の関連するオブジェクトの1つまたは複数のグラフになります。
データの多くは(永続的な状態がファイルまたはデータベースに格納されているかどうかに関わらず)アプリの永続的な状態の一部であり、データがアプリに読み込まれた後にモデルオブジェクトに存在している必要があります。
モデルオブジェクトは特定の問題領域に関連した知識や専門的技術を表しているため、類似した問題領域で再利用することができます。
『純粋な』モデルオブジェクトは、データを表示するビューオブジェクトへの明示的な接続を持っておらず、(ユーザインターフェイスや結果の提示に関連していない)データの編集をユーザに許可しています。

データを生成または変更するビュー層でのユーザのアクションは、モデルオブジェクトの作成または更新した結果を、コントローラオブジェクトを介して伝達します。
モデルオブジェクトが(ネットワーク接続経由で受信した新規データなどで)変更された場合、適切なビューオブジェクトを更新するコントローラオブジェクトに通知します。


ビューオブジェクト

ビューオブジェクトはユーザが見ることができるアプリのオブジェクトです。
ビューオブジェクトは自身がどのように描画され、ユーザのアクションに応答するかを知っています。
ビューオブジェクトの主な目的は、アプリのモデルオブジェクトからのデータを表示し、データの編集を可能にすることです。
にも関わらず、MVCアプリでのビューオブジェクトは通常モデルオブジェクトから分離されています。

通常ビューオブジェクトは再利用や再構成するため、ビューオブジェクトはアプリ間での一貫性を提供します。
iOSの場合はUIKitフレームワークがビュークラスのコレクションを提供し、OS XではAppKitフレームワークが同様のコレクションを提供します。
UIKitではビューオブジェクトは最終的にUIViewクラスから継承され、AppKitでは最終的にNSViewクラスから継承されます。

ビューオブジェクトはアプリのコントローラオブジェクトを介してモデルデータの変更について知るとともに、コントローラオブジェクトを介してアプリのモデルオブジェクトへ(テキストフィールドへのテキストの入力など)ユーザによって開始された変更について通信を行います。


コントローラオブジェクト

コントローラオブジェクトは、1つ以上のアプリのビューオブジェクトと1つ以上のモデルオブジェクト間を仲介します。
コントローラオブジェクトはビューオブジェクトがモデルオブジェクトの変更について、またはその逆について知らせるために介在する導管です。
またコントローラオブジェクトはアプリのタスクの設定や調整、そして他のオブジェクトのライフサイクルを管理も行います。

コントローラオブジェクトはビューオブジェクトで行われたユーザのアクションを解釈し、モデル層へ新規のまたは変更されたデータを通信を行います。
モデルオブジェクトが変更された場合に表示できるようにするため、コントローラオブジェクトは新しいモデルデータをビューオブジェクトへ通信します。



●デザインパターンと問題の解決

アプリのようなオブジェクト指向システムは動的です。
実行時にオブジェクトが行うことができる処理は、コンパイル時に設定された動作に制限されるものではありません。
オブジェクトは他のオブジェクトにメッセージを送信することができ、同じメッセージのターゲットを実行時の状況によって変更することもできます。
またオブジェクトはアプリの処理を効率的に遂行するため、様々な技術を使用し、実行時に他のオブジェクトの変数グループと協力することができます。
オブジェクトまたはオブジェクトのネットワークがこれを行うためには、デザインパターンに適応した多くの技術とフレームワークのアーキテクチャを活用する必要があります。

以下の項ではこれらの技術とアーキテクチャの多くを説明します。
貴方のObjective-Cプログラミングのツールキットの一部として考えてください。


デリゲーション:他のオブジェクトに代わって動作する

デリゲーションは、あるオブジェクトが他のオブジェクトから依頼された時に、デリゲートを呼び出して代わりに実行することです。
通常、委任するオブジェクトはフレームワークのオブジェクトです。
実行中のある時点でデリゲートへメッセージを送信し、メッセージはいくつかのイベントが発生していくつかの応答を要求することをデリゲートに伝えます。
デリゲート(通常はカスタムクラスのインスタンス)はメッセージによって呼び出されるメソッドを実装し、適切な値を返します。
多くの場合、その値はアクションを続行するかどうかを委任するオブジェクトに伝えるブール値です。

delegation_2x.png

デリゲーションは、(そのクラスのサブクラスを有すること無く)フレームワークのクラスの処理にアプリケーション固有の動作を導入する手段です。
これはフレームワークの動作を拡張して影響を与えるための、一般的かつ強力な設計です。

初めてのiOSアプリケーション』で作業をした時にHelloWorldアプリでHelloWorldAppDelegateオブジェクトを生成したことを思い出してください。
Xcodeはフレームワークのオブジェクトであるアプリのオブジェクトのデリゲートとして、自動的に割り当てます。
アプリのデリゲートはapplication:didFinishLaunchingWithOptions:を処理することができ、他のデリゲーションメッセージはアプリのオブジェクトによって送信されます。

デリゲーションには2つのプログラムの構成要素があります。
委任クラスはデリゲートへの参照を保持する(慣例によってdelegateと名付けられる)プロパティを定義する必要があります。
またデリゲートのクラスが採用しなければならないプロトコルを宣言する必要があります(次の項の『プロトコル』を参照してください)。
Cocoa TouchとCocoaフレームワークのクラスの多くは、アプリ固有のものでフレームワークの動作を強化するために、アプリが利用することができるアプローチとしてデリゲーションを提供します。

ただし、デリゲーションはフレームワークのクラスに限定されていません。
アプリ内の2つのカスタムオブジェクト間でデリゲーションを実装することができます。
Cocoa Touchアプリの一般的な設計では、子ビューコントローラが親ビューコントローラに何らかの値(通常はユーザが入力した値)を通信できるようにするための手段としてデリゲーションを使用します。


プロトコル:継承によって関連していないオブジェクト間の通信を有効にする

プロトコルは任意のクラスのメソッドを実装することができるようにする、プログラムインターフェイスの宣言です。
プロトコルに関連付けられたクラスのインスタンスは、プロトコルのメソッドを呼び出し、プロトコルを正式に採用し実装しているクラスによって返された値を取得します。
このオブジェクト間の通信は、XMLコードの解析やオブジェクトのコピーなどの特定の目的を助成します。
どちらのプロトコルインターフェイスのオブジェクトも、継承によって相互に離れて関連付けすることができます。
したがってプロトコルはデリゲーションとしてはサブクラス化の代替であり、多くの場合デリゲーションのフレームワークの実装の一部です。

protocol_2x.png

Appleが提供するフレームワークは多数のプロトコルを宣言します。
更に、貴方のアプリは貴方のクラスが採用することができるカスタムプロトコルを宣言することができます。
プロトコルは貴方のプログラミングツールキットの一部です。
Programming with Objective-C』ではプロトコルの包括的な説明がされています。


通知センター:関連するイベントのオブザーバへの通知

通知センターは、イベントのオブザーバに登録されているアプリ内の全てのオブジェクトにメッセージ(通知)を提供する、Foundationフレームワークのサブシステムです。
(プログラムはNSNotificationCenterクラスのインスタンスです。)
イベントは、例えばアプリがバックグラウンド状態になったり、またはユーザがテキストフィールドへ入力を開始するなど、アプリに発生する何かです。
通知はイベントが発生した、または発生しようとしていることをオブザーバに告げ、オブザーバに適切な方法で応答する機会を与えます。
通知センターによって提供される通知は、アプリ内のオブジェクト間の協調と結束を強めるための方法です。

notificationcenter_2x.png

例えばiOSアプリのビューコントローラは、仮想キーボードを収容するためにビューのジオメトリを調整する通知UIKeyboardWillShowNotificationを観測することができます。
この例が示すように、通知は特定のイベントを示す名前と、イベントが発生した、または発生しようとしているかどうかを持っています。
また通知センターに通知を投稿(または送信)するオブジェクトへの参照を保持し、補足情報の辞書を含むことができます。

全てのオブジェクトは通知を観測することができますが、受信するには登録する必要があります。
登録するには、通知を送付することによって呼び出されるメソッドを識別するセレクタを指定し、メソッドのシグネチャは単一のパラメータ(通知オブジェクト)を持っている必要があります。
登録する際は、オブザーバも投稿オブジェクトを指定することができます。

通知センターの通知はデリゲーションのメッセージに似ており、双方共に特定のイベントが発生した場合に任意のオブジェクトに送信されます。
ただし通知を処理するメソッドはデリゲーションのメソッドとは異なり、値を返すことはできません。
通知センターを経た通知は、デリゲーションと同様に同期します。

貴方のアプリのカスタムオブジェクトは独自の通知を定義および投稿することができ、貴方のアプリの他のカスタムオブジェクトは通知を観測することができます。


ターゲット-アクション:イベント発生時送信されるメッセージをカプセル化

ターゲット-アクションの設計は概念的には単純です。
オブジェクトはメッセージ式を構成する要素を格納し、特定のイベントが発生した時にこれらの要素と一緒にメッセージを送信します。
要素はメッセージ(アクション)を識別するセレクタとメッセージを受信するオブジェクト(ターゲット)です。
ターゲットのクラスはアクションとターゲットに対応するメソッドを実装しており、実行時にメッセージを受信した場合は、メソッドを実行することによってイベントに応答します。

ターゲット-アクションは、主にCocoa TouchとCocoaフレームワークの双方におけるコントロール機能です。
コントロールはユーザがアプリに意志を伝えるために(タップやドラッグなどの)操作をする、ボタンやスライダ、スイッチなどのユーザインターフェイスオブジェクトです。
Cocoa Touchコントロールはアクションとターゲットの両方を格納し、ほとんどのCocoaコントロールはターゲットとアクションを格納する1つ以上のセルオブジェクトと対になっています。

target_action_2x.png

いくつかのフレームワークはコントロール以外のオブジェクトでターゲット-アクションを使用します。
例えばUIKitフレームワークはジェスチャリコグナイザの設計にターゲット-アクションを使用しています。
ジェスチャリコグナイザオブジェクトがジェスチャを認識すると、ターゲットオブジェクトにアクションメッセージが送信されます。


キー値監視:値変更時にオブザーバへ通知

キー値監視(Key-value observingまたはKVO)は、オブジェクトが他のオブジェクトのプロパティを監視することを可能にするものです。
監視オブジェクトはプロパティの値が変更された時に通知します。
古い値が新しい値になったことを知るだけでなく、監視されているプロパティが(配列などの)対多関係の場合、変更に関与しているものを含むオブジェクトも知ることができます。
KVOは変更に同期したモデル、コントローラ、ビュー層のオブジェクトを保持することによって、よりまとまりのあるアプリにするのに役立ちます。

kvo_2x.png

NSNotificationCenterの通知と同様に、複数のKVOのオブザーバは単一のプロパティを監視することができます。
更に、KVOは通知名などの新しいAPIを必要とせずに、オブジェクトが任意のプロパティを監視することができるので、より動的です。
KVOは、全てのインスタンスの特定のプロパティを監視することを許可しない、軽量のPoint-to-Point通信メカニズムです。


デザインパターンに基づいた他のフレームワークの設計

Cocoa TouchとCocoaフレームワークには、次のようなデザインパターンに基づいた他の設計も含まれています。

  • ビュー階層
    アプリが提示するビューは視覚的に基づく階層構造に配置されたコンテナです。
    この形式はアプリが個々のビューとビューの構成物を一様に扱うことができます。
    階層のルートはウィンドウオブジェクトで、ルート下にある各ビューは1つの親ビューと0個以上の子ビューを持ちます。
    親ビューは子ビューを収納します。
    ビュー階層は描画とイベント処理の両方の構成要素です。

  • レスポンダチェーン
    レスポンダチェーンはチェーン内のあるオブジェクトがイベントを処理するまで、順次イベントまたはアクションメッセージを渡すことができる一連のオブジェクト(通常はビューやウィンドウ、ビューコントローラ、そしてアプリケーションオブジェクト自身)です。
    つまり協調的なイベント処理のメカニズムです。
    レスポンダチェーンはビュー階層に密接に関係しています。

  • ビューコントローラ
    UIKitとAppKitフレームワークは双方共にビューコントローラクラスを持っていますが、iOSでは特に重要です。
    ビューコントローラは、ビューのセットを提示および管理するためのコントローラオブジェクトの特殊な種類です。
    ビューコントローラオブジェクトは、コンテンツ関連のビューの管理と表示/非表示を調整するための基盤を提供します。
    ビューコントローラはアプリケーションのビューのサブ階層を管理します。

  • Receptionist
    Receptionistパターンは、アプリがある実行コンテキストから別の実行コンテキストにリダイレクト(または『跳ね返す』)する処理です。
    (実行コンテキストは主スレッドまたは副スレッドに関連付けられたディスパッチキューや操作キューです。)
    Receptionistパターンを適用する状況は、主にユーザインターフェイスを更新する操作など、主キュー上で実行する必要があるタスクが、副キューで実行されている処理に起因している場合です。

  • カテゴリ
    カテゴリはメソッドを追加することによってクラスを拡張する方法を提供します。
    デリゲーションと同様に、サブクラス化せずに動作のカスタマイズをすることができます。
    カテゴリは『Objective-Cコードの記述』で説明しているObjective-Cの特徴です。



参考文献

Apple/Start Developing iOS Apps Today

Apple/Streamline Your App with Design Patterns

0 CommentsPosted in 資料





コンパニオン20
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
03 | 2017/04 | 05
Sun Mon Tue Wed Thu Fri Sat
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 - - - - - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

コンパニオン20
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR