スキップしてメイン コンテンツに移動

Objective-Cの手習い:TemplateMethodパターン

今回はTemplateMethodパターン。 『Java言語で学ぶデザインパターン入門』をベースにしているので、コードの意味などはこちらのJava版のソースコードを参照ください。

まずは素直にJavaのコードを移植したパターン(TemplateMethod1)。

Objective-Cには言語として抽象クラスのサポートがない。概念なのでプログラマーが勝手にやれよということらしい。で、サンプルコードではAbstractDisplayという名前になっているが実際にはサブクラスで実装を期待するメソッドについては空メソッドを定義している。

    -(void) open { }
    -(void) print{ }
    -(void) close{ }

呼び出す側のメイン関数も以下の通り

    char c = 'H';
    id d1 = [[CharDisplay alloc] initWithChar: c];
    id d2 = [[StringDisplay alloc] initWithString:@"Hello World!"];
    AbstractDisplay* d3 = 
               [[StringDisplay alloc] initWithString:@"日本語でこんにちは"];

    [d1 display];
    [d2 display];
    [d3 display];

結果は以下のようになる。

    <<HHHHH>>
    +------------+
    |Hello World!|
    |Hello World!|
    |Hello World!|
    |Hello World!|
    |Hello World!|
    +------------+

    +------------------+
    |日本語でこんにちは|
    |日本語でこんにちは|
    |日本語でこんにちは|
    |日本語でこんにちは|
    |日本語でこんにちは|
    +------------------+

これだけでは面白くないので、Objective-Cのクラスクラスタを使ってFactory的に実装してみる。(TemplateMethod2)

まず、AbstractDisplayの+(id)allocを以下のように定義する。

    +(id)alloc
    {
      self = [super alloc];
      if([self isMemberOfClass:[AbstractDisplay class]]) {
         PlaceHolderDisplay* disp = [PlaceHolderDisplay alloc];
         return disp;       
      } else {
         return self;
      }
    }

解説すると、最初に呼ばれたときには素直に親クラスのallocを呼び出し、自身がAbstractDisplayだったときはPlaceHolderDisplayをallocして返し、AbstractDisplayでなかったときはそのまま自身を返す。

PlaceHolderDisplayでは、以下のように2つの初期化メソッドだけが定義されている。

    -(id)initWithString:(NSString*) str
    {
      self = [[super init] autorelease];
      StringDisplay* disp = [[StringDisplay alloc] initWithString:str];
      return disp;
     }
     -(id)initWithChar:(char)ch
     {
       self = [[super init] autorelease];
       CharDisplay* disp = [[CharDisplay alloc] initWithChar:ch];
       return disp;
     }

ここでやっていることも、初期化で呼び出された際それぞれ見合った子クラスのインスタンスを生成して返す。

Javaな人から見るとalloc、つまりコンストラクタで自分とは別の子クラスのインスタンスを生成して返すなど邪道に思えるが、こうすることにより呼び出し側は以下のようになりこれらの子クラスのxxxxDisplayなどを意識することなくAbstractDisplayクラスのみを使う感覚で使用できることになる。

    id d1 = [[AbstractDisplay alloc] initWithChar:c];
    id d2 = [[AbstractDisplay alloc] initWithString:@"Hello World!"];
    AbstractDisplay* d3 = [[AbstractDisplay alloc] initWithString:@"日本語でこんにちは"];

実際、Cocoa/FoundationのNSStringクラスなどは抽象クラスで上記と同じような構成でデータ格納形式に応じて子クラスを生み分けているようだ。

コメント

このブログの人気の投稿

WWDC 2010の予想

眠れないので、明日に迫ったWWDC2010の予想でもしてみよう。 もう確実なのがiPhone新モデルとiPhone OS 4.0の発表。 予想される大きな改良点は、 マルチタスクになる ホームにフォルダなどの概念が取り込まれ、UIが大きく変更される テザリングが可能となり iPhoneをWiFiルーター化できる iChatが組み込まれる Facebookとの連携が組み込まれる ファイルの同期がiPadのように組み込まれる iPadとの同期がMacなしで可能となる 既にiPhoneの3G上で動作するSkypeが発表されているのでインパクトは薄いかも知れないけれど、3G上で動作するVoIPとしてiChatが提供されればユーザーとコミュニケーション・ツールとしてのiPhoneの使い方は大きく変わりそうな気がしている。 その他には、Safari Extension、新Macbook Air、新Mac Proなどかな。iTunes.comも噂されている。そう言えば、MobileMeの無料化なんてのも噂としてあるが……

My name is E

E の名刺を作って、iPhoneの専用アプリを導入してみた。 写真のようにカードが表示されるので、相手に向かってiPhoneを振ってあげれば名刺が飛んでいくというインターフェイス。なにせiPhoneユーザーが周りにいないのでどうやって相手の認識しているか不明だけれど、おもしろいインターフェイス。 ちなみに、わたしの公開カードは http://eee.am/yostos

Thinkpad T42

新たに購入したお仕事用のPC Thinkpad T42が先週末届いた。 仕様は、Pentium-M 1.80GHz, 1400x1050の15型TFT液晶、メモリーは追加して1.5GB(増設用に2GBを用意していたが、秘書さんのPCが256MBで苦しんでいたので1GBあげてしまった)、指紋センサー付き。無線もEEE802.11a/b/g対応となった。 こうして、iBookと並べてみると対照的。天使と悪魔か…… 今まで使用してたT30と比較すると、多少CPUが早くなりUSBが2.0になり指紋センサーがついて、やけに軽くなった。腰痛持ちの私にとっては、重量がぐんと軽くなったのが一番うれしいか。それでも2kg以上あるが。 指紋センサーはパームレスト上に(写真でいうと右側)実装されている。付属のソフトで設定すると、起動時のBIOS、HDDのパスワード投入、WindowsXPのログイン用パスワード投入の代わりに、電源オン時の指紋照合一発で済ませることができる。センサーに読み込ませるためには、指を一定の角度でセンサーに向けてまっすぐに動かさないと誤認識される。多少コツが必要で偶に失敗する。指紋はいくつか指を登録できるので複数を登録しておいたほうが無難。 今回も新しいおもちゃになりそうな機能はいくつかついているのだが、2日くらいで飽きてしまった。仕事で使うには十分なスペックで、十分に快適。ちょっと前まではお仕事用のPCも結構愛着やこだわりを持っていたのだが、買い替えを行って新しいPCが来てもあまりワクワクしなくなった。最近は、2年に一度機械的に買い替えを行うような感じ。スペック的に見るとiBookなどと比べるまでもないほどはるかに重装備だが、iBookのほうが楽しい。 PCの価値はスペックだけでは語れないのだよ(ムスカ風)