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

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クラスなどは抽象クラスで上記と同じような構成でデータ格納形式に応じて子クラスを生み分けているようだ。

コメント

このブログの人気の投稿

Scrivener 日本語チュートリアル

(2022-01-11) 以前からコメントをいただいていましたが、反応できていなく申し訳ありません。 問い合わせが多いので、以下のブログに転載してチュートリアルもダウンロードできるようにしました。 転載先 先日から[試していたScrivenerだが、すっかり気に入り勢い余ってチュートリアルの日本語訳版を作ってしまった。 作者にコンタクトしたところ、「どうぞ、公開しておくれ!」と快く承諾をもらえたので公開しておく。 チュートリアル自体はわたしが慣れないBritish Englishで書かれているため、微妙なニュアンスは違っている箇所があるかもしれあない。また、チュートリアル自体に関係ない言い回しなどは、端折ったり日本語に合うようにゆがめたりしている。誤りがあれば指摘ください。 Scrivener-Tutorial-Japanese.dmg(リンクを切りました。転載先をごらんください。) ちなみに作者のKeithは豪気にもライセンス進呈を申し出てくれたが、入れ違いで購入してしまっていたわたし…… (2010-09-20) 「 design non design 」で紹介いただきました。

スターシップ・トゥルーパーズ

『スターシップ・トゥルーパーズ』を見る。 1997年の作品で15年近く昔の映画だからか? いや、制作にかかわってるフィル・ティペットが関わった『ジェラシック・パーク』は1993年のはずだ。原作がヘボなのか? いや、原作はハイラインの『宇宙の戦士』のはずだ、あれは昔、俺も読んだぞ…… なんだろう? このやるせなさは。 CGもそんなに古さを感じさせないし、ストーリーもまぁ設定がベタなところはあるが構想はでかい。うーん 問題なのは脚本と演出と演技か。見てる印象は、アホで安直なアメリカンな80年代以前の古くさいSF映画だ。それがもしかしたら狙った演出なのかと思う節もあるが、狙いも分からん。質のいい大阪漫才を観たあとで、くそ下手なボケにラフトラック無理矢理入れたシットコムを見せられた気分だ。 たとえば、こんな具合…… 宇宙戦艦に巨大アステロイドが急接近。未来の宇宙戦艦がそんな急接近されるまで気付かず、パイロットが目視で発見というところは許そう。今にも衝突しそうで警報がバンバン鳴っている中、回避操作に取り掛かったヒロインのセリフが「緊急回避、3、2、1、ゴー!」…… 数えてないで、早くハンドル切ってよ。 揚げ句の艦橋上部がへし折れて宇宙の大海原で通信機能が失われおそらく何名か亡くなっているのに、館長のセリフが「助かったわ、パイロットのおかげよ、ナイスジョブ」…… いや、あの3秒がなければ無傷だったと思うよ、戦艦も。 このヒロインは常にこんな調子。 戦艦が爆発しかけて脱出ボートも次々の火に巻き込まれていくなか、脱出ボートに乗り込んで礼儀正しくヘルメットして「用意はいい、いくわよ」、「ガァーーーーーーーーーーーーーーー(キャノピーを閉める音)」「発射!」…… 早く逃げろよ、イライラする。 まぁ、こういう楽しみ方をするならお勧めです。 敵が「虫」なのだが、地上から攻撃出来る対宇宙戦艦の屁をこく虫がいるとか、相手が虫なのに死んでもいない主人公を死んだことにして諜報戦でもやってるつもりの歩兵隊とか…… スターシップ・トゥルーパーズ [DVD] posted with ama...

iOS5に上げたらやっておくべきこと

忘備録。 今さらながら、iOS5にバージョンアップしたときにやっておくべきことを書き出しておこう。わたし自身はiPhone4持ちですが、3Sでも結構動いている模様なので、参考にどうぞ。 通知関連 iOS5になって通知機能が充実してMobile機器としてさらに使いやすくなったが、反面バッテリーを食う原因ともなっているようだ。不用なアプリの通知については個別にオフに設定したほうがよいだろう。 また、「緊急地震速報」はバージョンアップした場合はデフォルトではオフになっています。但し書きに「設定をオンにした場合バッテリーも持ち時間が短くなる場合があります」と書かれている。今沖縄住まいなのでとりあえずオフのままにしておこう。 位置情報サービス 先日報告されたiPhone 4Sのバッテリー異常消費の原因とも見なされている機能だが、ネットではこのシステムサービスの設定が原因とささやかれていたものだ。まずはアプリの一覧が表示されているが、位置情報が不用と思われるアプリについてはセキュリティの観点からもオフにしておきましょう。 さて、一番下にある「システムサービス」だが、コンパスの調整以外はすべてオフでよいと思われる。ちなみに「位置情報に基づくiAd」は無料アプリに表示される広告に位置情報が加味されるサービス。「携帯電話通信網検索」はキャリアは固定だろうからあまり意味がない。「時間帯の設定」は海外旅行に頻繁に行く人しか意味がない。「渋滞状況」は日本ではサービスが始まっていない。 「システムサービス」の「診断/使用状況」はAppleに自動送信されている情報に位置情報を含めるための設定。Appleには悪けれど、そうでなくてもAppleにたくさんお布施をしている我が身なればさらに通信費まで負担して貢献する気持ちにはなれない。よって、「診断/使用情報」を送る設定自体をオフにしちゃいましょう。変更は「設定」> 「情報」> 「診断/使用状況」 で「送信しない」を選択すればよい。 Spotlight検索 インデックス構築にバッテリーが消費されるらしいので不用なものはチェックを外そう。「設定」>「一般」>「Spotlight検索」で。わたし自身ほとんど利用しないので全部外してしまった。 キーボード設定 不用なキーボードをオフっておくのはこれまで通りだが、今回日本語に入力でこれまでの「かな入力」の他に...