Compositeパターンとは

Compositeは、階層関係を実現するためのパターンだ。親となるオブジェクトは、同じクラスの子オブジェクトを持つことができる。

例によって、GoF本の例から見てみよう。取り上げられているのは、ドロー系のグラフィックツールだ。このツールでは、線、四角、テキストといったプリミティブを組み合わせていくことで、画像を作り上げていく。だが、これらのオブジェクトに求められる機能は、絵を描くことだけではない。他のプリミティブを内部に配置する、コンテナとしての機能も求められるのだ。

このような要求に応えるために、まず描画機能を定義するGraphicsというプリミティブを定義する。それを継承する形で、Line、Rectangle、Textといったクラスを作っていく。それに加えて、コンテナとなるPictureクラスを、これもまたGraphicsのサブクラスとして定義する。Pictureクラスは、子オブジェクトしてGraphicsの配列を持つことができる。これにより、階層関係が実現できる。

ポイントは、PictureはGraphicsのサブクラスなので、Picture自身を子オブジェクトとして保持できることだ。この再帰的な仕組みにより、柔軟な階層構造を実現できることになる。

Compositeパターンの登場人物

このようなCompositeパターンを作るための、登場人物を定義しよう。

まず、階層関係の基本となるクラスとして、Componentを定義する。Componentを継承したクラスが、階層関係の中に登場する。Componentでは、このモデルで必要となる基本的なメソッドを定義する。Componentを継承したクラスで、これらをオーバーライドすることになる。

Componentを継承したクラスは、2つ用意しよう。1つは、階層関係の末端となるオブジェクト。これをLeafとする。もう1つは、コンテナとして他のComponentを持つことができるクラス。これがCompositeとなるわけだ。

これらの関係をまとめると、次のようになるだろう。

Compositeは、子となるComponentを複数持つことができる。この中に、Composite自身を持つことができるのが重要なところだ。

Compositeパターンの実装

では、このCompositeパターンをObjective-Cで実装してみよう。

まずは、Componentからだ。ComponentObjectというクラスを定義する。本当はComponentクラスにしたかったのだが、Cocoa環境下ではすでにこの名前は使われているので、ComponentObjectとした。

ComponentObjectでは、基本となる操作メソッドを定義する。ここでは、operationというメソッドを定義した。

List 1.

@interface ComponentObject : NSObject
{
}

- (void)operation;

@end

次に、Componentを継承したクラスを定義しよう。まず、Leafだ。Leafは階層関係の末端となるので、子は持たない。目的は、独自のoperationメソッドを実装することになる。

List 2.

@interface Leaf : ComponentObject
{
}
@end

@implementation Leaf

- (void)operation
{
    // operationの実装
}

@end

そして、Compositeクラスを実装する。このクラスもComponentを継承する。そして、コンテナとしての役割を果たすために、子となるオブジェクトを保持できるようにしよう。そのためには、インスタンス変数として、配列であるNSMutableArrayを持つ事にする。さらに、子オブジェクトにアクセスするためのメソッドも用意しよう。add:、remove:、childAtIndex:といったメソッドを定義しておく。

List 3.

@interface Composite : ComponentObject
{
    NSMutableArray* children;
}

- (void)add:(ComponentObject*)component;
- (void)remove:(ComponentObject*)component;
- (id)childAtIndex:(int)index;
@end

Compositeに必要なメソッドを実装していこう。まず、子となるオブジェクトにアクセスするためのメソッドだ。これらでは、子を保持している配列を操作することになる。

List 4.

- (void)add:(ComponentObject*)component
{
    [children addObject:component];
}

- (void)remove:(ComponentObject*)component
{
    [children removeObject:component];
}

- (id)childAtIndex:(int)index
{
    return [children objectAtIndex:index];
}

そして、Component独自の処理を行うoperationメソッドだ。ここには、Composite独自の処理を記述する。それに加えて、保持している子オブジェクトにもoperationメソッドを伝播させる必要がある。

List 5.

- (void)operation
{
    // Composite独自の処理
    ...

    // 子のoperationを呼び出す
    NSEnumerator*       enumerator;
    ComponentObject*    component;
    enumerator = [children objectEnumerator];
    while (component = [enumerator nextObject]) {
        [component operation];
    }
}

Objective-CでのCompositeパターンの実装は、このようなものになるだろう。次回は、Cocoaでの実装の紹介に移ろう。もちろん、CompositeといえばModel/View/ControllerのViewになる。

提供: 毎日キャリアバンク

毎日キャリアバンクではITエンジニア出身のキャリアコンサルタントで形成する IT専門のチームを編成し、キャリアに応じた専任コンサルタントがご相談を承り ます。キャリアチェンジから市場価値の可能性、ご収入などの相談から面接のア ドバイスまでお気軽にご相談ください。求人情報誌や転職情報サイトなどで一般 に公開されていないような「急募求人案件」も随時ご紹介が可能です。まずはご 登録ください!