【コラム】

ダイナミックObjective-C

120 デザインパターンをObjective-Cで - Visitor (1)

    木下誠  [2009/01/13]

    23種類のデザインパターンを取り上げるこの連載も、いよいよ最後のパターンとなった。Visitorパターンである。最後となる「訪問者」を紹介しよう。

    Visitorとは

    ある構造を持つオブジェクトの集合があり、そのそれぞれのオブジェクトに対して処理を行う事を考えてみよう。たとえば、木構造である。木構造では、ノードと呼ばれるオブジェクトが、樹形図を構成している。ここに含まれるオブジェクトを走査し、ノードの種類に応じて処理を行っていくものだ。こういったプログラミングには、構文木を解析するコンパイラや、HTMLのDOMツリーに対する処理などがあるだろう。

    このとき、処理を行うのはどのオブジェクトにすべきであろうか。一つの考え方は、ノードオブジェクトに行わせるというものである。自分自身で処理を行う訳だから、筋は通っているだろう。だがこの方法だと、ノードという木構造を表す機能と、コンパイルといった特定の処理が、同一のクラスになってしまう。クラスの再利用性を考えると、構造を表すクラスと、処理を行うクラスは切り離しておきたい。

    そこで、オブジェクトの走査を行うときに、それぞれのオブジェクトを訪れて処理を行う「訪問者」となるクラスを作ろう。これがVisitorパターンの考え方だ。Visitorパターンを使うときは、走査を行いながらそれぞれのオブジェクトにVisitorを訪問させてやる。このVisitorの中で、処理を行うのだ。

    Visitorパターンの登場人物

    Visitorパターンに登場するクラスを紹介しよう。まず、処理を行う対象となるクラスがある。これをElementクラスとしよう。そして、Elementクラスに対して処理を行うクラスを、Visitorクラスとする。

    また、Elementの集合を管理する、構造を定義するものもあるだろう。これは、Object Structureと呼ぼう。たとえばObject Strctureの実装として、Iteratorパターンを適用するという事も考えられるだろう。

    これらを図示すると、次のようになる。

    ここで、VisitorとElementの間に参照関係がないことに注意してほしい。Object Structureの中からElementを走査してVisitorを適用させるのは、ClientまたはObject Structureの仕事になる。

    Visitorパターンの実装

    では、Objective-CでのVisitorパターンの実装を紹介しよう。

    まず、Elementクラスを定義する。Elementクラスには、Visitorを適用させるためのメソッドが必要だ。これを、accept:としよう。具体的なサブクラスとして、ElementAとElementBを定義しておく。

    List 1.

    @interface Element : NSObject
    {
    }
    
    // Visitorクラスの訪問を受け付ける
    - (void)accept:(Visitor*)visitor;
    
    @end
    
    @interface ElementA : Element
    {
    }
    @end
    
    @interface ElementB : Element
    {
    }
    @end
    

    Elementクラスの実装の前に、Visitorクラスを定義しよう。Visitorクラスには、Elementを処理するためのメソッドを定義する。これを、visitElementA:、visitElementBとしよう。

    @interface Visitor : NSObject
    {
    }
    
    - (void)visitElementA:(ElementA*)element;
    - (void)visitElementB:(ElementB*)element;
    
    @end
    

    このvisitElementA:とvisitElementB:を、Elementクラスが呼び出すことになるのだ。

    では、Elementクラスの実装を行おう。Elementクラスに定義されているaccept:メソッドの中で、VisitorクラスのvisitElementA:またはvisitElementB:を呼び出すのだ。ElementAとElementBとで、それぞれaccept:をオーバーライドすることで実現しよう。

    @implementation ElementA
    
    - (void)accept:(Visitor*)visitor
    {
        // Visitorクラスに訪問させる
        [visitor visitElementA:self];
    }
    
    @end
    
    @implementation ElementB
    
    - (void)accept:(Visitor*)visitor
    {
        // Visitorクラスに訪問させる
        [visitor visitElementB:self];
    }
    
    @end
    

    これで、VisitorクラスがElementを処理出来るようになる。VisitorクラスのvisitElementA:、およびvisitElementB:では、それぞれのElementの種類に応じて処理を行うことになる。

    これがVisitorパターンの実装となる。次回は、CocoaフレームワークでのVisitorパターンを実現している例を紹介しよう。

    新着記事

    特設サイトの情報

      求人情報

      人気記事

      一覧

      イチオシ記事

      新着記事

      特別企画

      転職ノウハウ

      あなたの仕事適性診断

      4つの診断で、自分の適性を見つめなおそう!

      Heroes File ~挑戦者たち~

      働くこと・挑戦し続けることへの思いを綴ったインタビュー

      はじめての転職診断

      あなたにピッタリのアドバイスを読むことができます。

      転職Q&A

      転職に必要な情報が収集できます

      スカウト転職する

      企業からアプローチのメッセージが届きます。

      マイナビニュースマガジン