【コラム】

ダイナミックObjective-C

70 デザインパターンをObjective-Cで - Bridge (2)

 

70/121

今回は、BridgeパターンのCocoaでの実装例を調べてみよう。取り上げるのは、GoF本でも使用例として言及されている、NSImage/NSImageRepクラスだ。

NSImageとNSImageRep

NSImageは、名前からも想像がつくと思うが、画像を取り扱うためのCocoaのクラスだ。画像ファイルの読み込み、画像の画面への描画などを担当する。アプリケーションを作るときは、なくてはならないクラスだ。

このNSImageのようなクラスを実装する事を考えてみよう。少し経験を積んだプログラマならば、これはとても大変だという事が分かると思う。画像のためのクラスには、あらゆるタイプの画像を扱えるようにする事が求められるからだ。JPEGやPNGといったビットマップの画像だけではない。PDFのように命令が埋め込まれているタイプのもの、描画ルーチンをプログラムとして与えることができるものなども含まれるのだ。

このような要求に応えるために、Cocoaでは、画像に関するクラスを高レベルのものと低レベルのものとに分けることになった。高レベルのクラスとはNSImageであり、アプリケーションから利用する事を目的とする。画像の読み込みや描画のためのAPIを提供する。そして、実際のファイルの読み込みや描画処理を行うのが、低レベルのクラスであるNSImageRepになるのだ。この、NSImageとNSImageRepの関係が、GoF本でいうところのBridgeパターンに相当する。

NSImageRepのサブクラス

NSImageRepの具体的なイメージをつかんでもらうために、どのようなクラスが用意されているのか紹介しよう。NSImageRepクラスは低レベルクラスのAPIを定義し、実際の処理はそのサブクラスで行う。

NSBitmapImageRep

GIF、JPEG、TIFF、PNGといったビットマップ画像を取り扱う。

NSPDFImageRep

PDFフォーマットを取り扱う。ちなみに、このクラスは画像としてPDFを表示することだけを目的としている。PDFを本格的に活用するならば、PDF Kitフレームワークを使うのが適当だろう。

NSEPSImageRep

Encapsulated PostScript(EPS)画像を取り扱う。

NSPICTImageRep,

AppleのPICTフォーマットを取り扱う。

NSCIImageRep

CoreImageのCIImage画像を取り扱う。

NSCustomImageRep

描画を行なうカスタムルーチンを指定できる。

NSCachedImageRep

上記のImageRepクラスがレンダリングした結果を、キャッシュとして利用できる。

単なるビットマップ画像だけではなく、様々なタイプの画像を想定している事が分かるだろう。

BridgeパターンとしてのNSImage

では、NSImage/NSImageRepを、Bridgeパターンとして解釈してみよう。下の図のようになるだろう。

NSImageはAbstractionとなる。特にサブクラスは用意されていないので、NSImageをそのまま使うことになる。そして、NSImageRepはImplementorとなる。こちらでは、多くのサブクラスが用意されることになる。

NSImageとNSImageRepで定義されているメソッドも少し紹介しよう。NSImageでは、画面への描画を行なうメソッドして、次のようなメソッドが用意されている。

List 1. (NSImage.h)

- (void)drawAtPoint:(NSPoint)point fromRect:(NSRect)srcRect operation:(NSCompositingOperation)op fraction:(float)delta
- (void)drawInRect:(NSRect)dstRect fromRect:(NSRect)srcRect operation:(NSCompositingOperation)op fraction:(float)delta

drawAtPoint:fromRect:oepration:fraction:は、ポイントを指定して描画するもの。drawInRect:fromRect:operation:fraction:は、領域を指定するものだ。後者では、領域の大きさを変更する事で、拡大/縮小もできる。どちらのメソッドも、source overやsource copyといった合成モードの指定、および透明度の指定が行える。これが、ユーザに提供される、描画のための高レベルAPIということになる。

次に、NSImageRepのメソッドを紹介しよう。まず、画像の情報を得るためのメソッドとして、次のようなものが提供されている。

List 2. (NSImageRep.h)

- (int)bitsPerSample
- (NSString*)colorSpaceName
- (BOOL)hasAlpha
- (BOOL)isOpaque
- (int)pixelsHigh
- (int)pixelsWide

画像のピクセル数、ビットあたりのサンプル数、透明度の有無といった、画像の基本的な情報を調べることができる。そして、画像を描画するためのメソッドとしては、次のものがある。

List 3. (NSImageRep.h)

- (BOOL)draw
- (BOOL)drawAtPoint:(NSPoint)point
- (BOOL)drawInRect:(NSRect)rect

これらを呼ぶ事で、実際の描画が行われる。

ここで、NSImageRepの描画メソッドは、NSImageのものと比べると機能が少ない事が分かるだろう。これは、NSImageRepが低レベルのAPIであり、画像を描画するためのプリミティブなものだけが用意されているためだ。合成や透明といった複雑な描画は、NSImageのレイヤで行われることになる。

Bridgeパターンの用語を使うならば、Implementorでは画像描画の実装に必要な機能を抽象化し、Abstractionでは実装に依存しない抽出された描画APIを提供している、と説明できるだろう。実装を分離するという、Bridgeパターンの目的にぴったりはまっている例である。

複数のNSImageRep

NSImage/NSImageRepの関係では、特筆しておきたい事が一つある。NSImageは、NSImageRepのインスタンスを、1つではなく複数持つことができるのだ。これは、画像を出力するデバイスに応じて、適切なNSImageRepを選択できるようにするための仕組みだ。具体的には、スクリーンかプリンタかによって、変わることになるだろう。

適切なNSImageRepを取得するために、NSImageには次のようなメソッドがある。

List 4. (NSImage.h)

- (NSImageRep*)bestRepresentationForDevice:(NSDictionary*)deviceDescription

引数としてデバイスの情報を渡し、それに応じた一番適切なNSImageRepを返すものだ。これにより、プログラマは出力先がスクリーンかプリンタかを気にする事なく、画像の描画を行なうことができる。

GoF本でも指摘されているが、複数のImplementorを切り替えることができるというのは、Bridgeパターンの興味深い拡張になるだろう。

70/121

インデックス

連載目次
第121回 デザインパターンをObjective-Cで - Visitor (2)
第120回 デザインパターンをObjective-Cで - Visitor (1)
第119回 デザインパターンをObjective-Cで - Template Method (1)
第118回 デザインパターンをObjective-Cで - Strategy (1)
第117回 デザインパターンをObjective-Cで - State (1)
第116回 デザインパターンをObjective-Cで - Interpreter (2)
第115回 デザインパターンをObjective-Cで - Interpreter (1)
第114回 デザインパターンをObjective-Cで - Mediator (3)
第113回 デザインパターンをObjective-Cで - Mediator (2)
第112回 デザインパターンをObjective-Cで - Mediator (1)
第111回 デザインパターンをObjective-Cで - Observer (3)
第110回 デザインパターンをObjective-Cで - Observer (2)
第109回 デザインパターンをObjective-Cで - Observer (1)
第108回 Fast Enumeration (4) - Fast Enumerationに対応するクラスの実装
第107回 Fast Enumeration (3) - Fast Enumerationのソースコード
第106回 Fast Enumeration(2) - NSFastEnumerationプロトコル
第105回 Fast Enumeration(1) - 速い列挙子
第104回 プロパティ(4) - プロパティの属性
第103回 プロパティ(3) - ドット演算子
第102回 プロパティ(2) - プロパティの宣言
第101回 プロパティ(1) - インスタンス変数のアクセス制御
第100回 ガベージコレクション(5) - コピーGCとコンパクション
第99回 ガベージコレクション (4) - マーク・アンド・スイープ
第98回 ガベージコレクション(3) - 保守的でありながらオブジェクト的
第97回 ガベージコレクション (2) - 実体であるlibauto
第96回 ガベージコレクション (1) - GCのためのAPI
第95回 デザインパターンをObjective-Cで - Memento (2)
第94回 デザインパターンをObjective-Cで - Memento (1)
第93回 デザインパターンをObjective-Cで - Chain of Responsibility (5)
第92回 デザインパターンをObjective-Cで - Chain of Responsibility (4)
第91回 デザインパターンをObjective-Cで - Chain of Responsibility (3)
第90回 デザインパターンをObjective-Cで - Chain of Responsibility (2)
第89回 デザインパターンをObjective-Cで - Chain of Responsibility (1)
第88回 デザインパターンをObjective-Cで - Command (5)
第87回 デザインパターンをObjective-Cで - Command (4)
第86回 デザインパターンをObjective-Cで - Command (3)
第85回 デザインパターンをObjective-Cで - Command (2)
第84回 デザインパターンをObjective-Cで - Command (1)
第83回 デザインパターンをObjective-Cで - Iterator (2)
第82回 デザインパターンをObjective-Cで - Iterator (1)
第81回 デザインパターンをObjective-Cで - Proxy (3)
第80回 デザインパターンをObjective-Cで - Proxy (2)
第79回 デザインパターンをObjective-Cで - Proxy (1)
第78回 デザインパターンをObjective-Cで - Flyweight (2)
第77回 デザインパターンをObjective-Cで - Flyweight (1)
第76回 デザインパターンをObjective-Cで - Facade (1)
第75回 デザインパターンをObjective-Cで - Decorator (2)
第74回 デザインパターンをObjective-Cで - Decorator (1)
第73回 デザインパターンをObjective-Cで - Composite (2)
第72回 デザインパターンをObjective-Cで - Composite (1)
第71回 デザインパターンをObjective-Cで - Bridge (3)
第70回 デザインパターンをObjective-Cで - Bridge (2)
第69回 デザインパターンをObjective-Cで - Bridge (1)
第68回 デザインパターンをObjective-Cで - Web Kitを考える Adapter (4)
第67回 デザインパターンをObjective-Cで - Adapater(3)
第66回 デザインパターンをObjective-Cで - Adapater (2)
第65回 デザインパターンをObjective-Cで - Adapter (1)
第64回 デザインパターンをObjective-Cで - Factory Method (4)
第63回 デザインパターンをObjective-Cで - Factory Method (3)
第62回 デザインパターンをObjective-Cで - Factory Method (2)
第61回 デザインパターンをObjective-Cで - Factory Method (1)
第60回 デザインパターンをObjective-Cで - Prototype (4)
第59回 デザインパターンをObjective-Cで - Prototype (3)
第58回 デザインパターンをObjective-Cで - Prototype (2)
第57回 デザインパターンをObjective-Cで - Prototype (1)
第56回 デザインパターンをObjective-Cで - Builder (2)
第55回 デザインパターンをObjective-Cで - Builder (1)
第54回 デザインパターンをObjective-Cで - Abstract Factory (2)
第53回 デザインパターンをObjective-Cで - Abstract Factory (1)
第52回 デザインパターンをObjective-Cで - Singleton (3)
第51回 デザインパターンをObjective-Cで - Singleton (2)
第50回 デザインパターンをObjective-Cで - Singleton (1)
第49回 デザインパターンで読み解くCocoa
第48回 F-Script - CocoaとObjective-Cのスクリプティング環境
第47回 AspectCocoa (5) - インプットマネージャとの連携
第46回 AspectCocoa (4) - AspectCocoaの実例
第45回 AspectCocoa (3) - フォワーディングとポージングの利用
第44回 AspectCocoa (2) - IMPによるアスペクト指向の実現
第43回 AspectCocoa (1) - Objective-CとCocoaによるアスペクト指向
第42回 SIMBLでハックを管理
第41回 インプットマネージャから侵入
第40回 Toll-free bridge (3) - Objective-Cメソッドの処理
第39回 Toll-free bridge (2) - Core Foundationのisaフィールド
第38回 Toll-free bridge(1) - 変換コスト0のブリッジ
第37回 Core Foudation (5) - インスタンスの実装
第36回 Core Foudation (4) - 多態性の実現
第35回 Core Foundation(3) - クラスの定義
第34回 Core Foundation(2) - C言語によるオブジェクト
第33回 Core Foundation(1) - Core Foundation誕生前夜
第32回 抽象クラスとクラスクラスタ
第31回 ランタイムAPIでさらに動的に(5) - インスタンス変数に動的にアクセス
第30回 ランタイムAPIでさらに動的に(4) - インスタンス変数の定義を調査
第29回 ランタイムAPIでさらに動的に(3) - メソッドの実装の置換
第28回 ランタイムAPIでさらに動的に(2) - メソッドの追加
第27回 ランタイムAPIでさらに動的に(1) - 動的なクラスの作成
第26回 メッセージ送信(4) - メッセージ送信の流れと関数呼び出しとの違い
第25回 メッセージ送信(3) - メソッドのキャッシング
第24回 メッセージ送信(2) - メソッドリストからメソッドを検索する
第23回 メッセージ送信(1) - objc_msgSendの実装
第22回 メソッドとは何か(5) - メソッドの実装
第21回 メソッドとは何か(4) - セレクタの実体
第20回 メソッドとは何か(3) - メソッドの型を読み解く
第19回 メソッドとは何か(2) - メソッドを取得する
第18回 メソッドとは何か(1) - メソッド、セレクタ、メソッドの実装
第17回 クラスとは何か(4) - Objective-Cにおけるオブジェクトとは何か?
第16回 クラスとは何か(3) - メタクラスと親クラス
第15回 クラスとは何か(2) - クラス情報に直接アクセスする
第14回 クラスとは何か(1) - Mac OS X/Objective-Cにおけるクラスの実装を読む
第13回 Objective-Cのエンジン部 - ランタイムに踏み込む
第12回 ポージングで乗っ取り
第11回 2つのプロトコルの使い分け
第10回 非形式プロトコル - もう1つのプロトコル
第9回 プロトコルが必要とされた背景とは? - なぜあえて静的な型を?
第8回 カテゴリ - 動的なメソッドの追加によるクラスの拡張
第7回 Objective-Cと様々な言語のブリッジ - PyObjC、RubyCocoa……
第6回 Cocoa-Javaの挑戦とは? - 似て非なるセレクタとリフレクション
第5回 ターゲット/アクションパラダイム(2) - その利点を徹底検証
第4回 ターゲット/アクションパラダイム(1) - 動的特性を利用したデザインパターン
第3回 Cocoa実現の肝 - クラスとそのメソッドの調査方法をチェック
第2回 Objective-Cの動的型付け
第1回 CocoaとObjective-Cと動的なオブジェクト指向 - Cocoaハックの第1歩

もっと見る



転職ノウハウ

あなたが本領発揮できる仕事を診断
あなたの仕事適性診断

シゴト性格・弱点が20の質問でサクッと分かる!

「仕事辞めたい……」その理由は?
「仕事辞めたい……」その理由は?

71%の人が仕事を辞めたいと思った経験あり。その理由と対処法は?

3年後の年収どうなる? 年収予報
3年後の年収どうなる? 年収予報

今の年収は適正? 3年後は? あなたの年収をデータに基づき予報します。

激務な職場を辞めたいが、美女が邪魔して辞められない
激務な職場を辞めたいが、美女が邪魔して辞められない

美人上司と可愛い過ぎる後輩に挟まれるエンジニアの悩み

人気記事

一覧

イチオシ記事

新着記事

好きな人の物を盗むのは“あるある”?不倫×SF描く米代恭、村田沙耶香とトーク
[23:54 7/23] ホビー
[LoVendoЯ]ギター担当の魚住有希が9月卒業を発表 今後はギタリストとして海外での勉強も視野
[23:51 7/23] エンタメ
高田桂「あねコン」1巻、狐に憑かれた義姉とのラブストーリー
[22:41 7/23] ホビー
あの日あの時あのコンピュータ 第13回 「8ビット御三家」最終形への夜明け前(その2) - NEC「PC-8001」
[21:04 7/23] パソコン
『おそ松さん』よりひょこっとラバーストラップの第2弾が登場
[20:00 7/23] ホビー

求人情報