図1●オブジェクト指向プログラミングは思いやりだ
図1●オブジェクト指向プログラミングは思いやりだ
[画像のクリックで拡大表示]

 連載の第1回で一覧表に示したとおり、GoFの23種類のデザインパターンは、「生成に関するパターン」「構造に関するパターン」そして「振る舞いに関するパターン」の3つに大きく分けられます。このことから、OOPに関するとても重要なヒントが得られます。それは、OOPを上手に実践するには、生成(オブジェクトを生成する方法)、構造(クラスの関連付け方)、そして振る舞い(オブジェクト間のメッセージの渡し方)を工夫すればよいということです。これら3つを重要視することが、他の技法にはないOOPらしさなんだとも言えるでしょう。たったの3つだけだと思うと、ずいぶん気持ちが楽になりますね。今回紹介するBuilderパターンとPrototypeパターンは、どちらも生成に関するパターンに属するものです。どんな工夫なのか、順番に説明しましょう。

【お役立ち度】★★★★★
●様々なオブジェクトを作ってくれるBuilder パターン

 Builder (構築者)パターンは、様々なバリエーションでオブジェクトを生成する「ビルダクラス」と「ディレクタクラス」を用意しておくというアイディアです。何事においても、物づくりには職人さんと現場監督(管理者)さんが必要でしょう。職人さんに相当するのがビルダクラスで、現場監督さんに相当するのがディレクタクラスです。様々なバリエーションとは、生成時の状態(オブジェクトが持つフィールドの初期値)が異なるオブジェクトという意味です。

 リスト1[拡大表示]をご覧ください。これは、筆者が時々たしなむ飲み物を表すクラスです。実用的なプログラムではないかもしれませんが、様々なバリエーションのオブジェクトをイメージしていただくには好例でしょう。4つの引数があるコンストラクタを使ってnew Drink(50, 0, 0, 0)というオブジェクトを生成すれば、ウイスキーだけのロックになります。new Drink(20, 80, 0, 0)なら炭酸水で割ったハイボールです。new Drink(20, 0, 80, 0)なら水割りで、new Drink(20, 0, 0, 80)ならお湯割です。皆さんは、もっと濃いのがお好きかもしれませんが。

リスト1●飲み物を表すDrinkクラス

public class Drink
{
    // フィールド
    public int whiskey; // ウイスキーの量(cc)
    public int soda; // 炭酸水の量(cc)
    public int mizu; // 水の量(cc)
    public int oyu; // お湯の量(cc)

    // コンストラクタ
    public Drink(int w, int s, int m, int o)
    {
        // フィールドに初期値を設定する
        whiskey = w;
        soda = s;
        mizu = m;
        oyu = o;
    }
}

 クラスを使う人に、様々なバリエーションでコンストラクタを呼び出していただくのでは申し訳ありません。クラスを作る人が、ビルダクラスとディレクタクラスで準備をしておいてあげましょう。ビルダクラスは、先ほどの様々なパターンでオブジェクトを生成するメソッドを提供するようにします。RockBuilder、HighbollBuilder、MizuwariBuilder、OyuwariBuilderといった名前で、複数のビルダクラスを作っておきましょう。クラスを使う人が、これらのビルダクラスを直接利用しても構いません。ただし、複数のビルダクラスをまとめて管理するディレクタクラスを作っておいた方が、より使いやすくなります。ぜひ、そうしてください。

 Builder パターンのキモは、カプセル化(データや処理手順の隠蔽)にあります。クラスを使う人は、目的のオブジェクトを生成するのに、どのようにフィールドを設定すればよいかを知らなくてもOKなのです。すなわち、楽ができます。お酒の場合も、バーテンダーさんにお任せすれば、望みの飲み物を作ってもらえますよね。私たちは、レシピを知らなくて済むのです。とっても便利なBuilderパターンの評価は、星5つの満点です。

【お役立ち度】★★★★★
●自分のクローンを生成するPrototypeパターン

 Prototypeパターンは、同じクラスでいくつかのバリエーションのオブジェクトをたくさん作るときに便利なものです。あらかじめ、それぞれのバリエーションのオブジェクトを1つずつ作っておきます。このオブジェクトがプロトタイプ(原形)というわけです。そこから先は、必要に応じてプロトタイプのクローン(コピー)を作って行きます。

 Prototypeパターンを実現するには、クラスの中に自分のクローンを返すメソッドを用意しておきます。クローンとは、フィールドの値が等しいオブジェクトのことです。たとえば、先ほどBuilderパターンの例であげたDrinkクラスなら、クローンを返すcloneメソッドをリスト2[拡大表示]のように記述できます。自分のフィールドの値を使ってオブジェクトを生成するだけです。cloneメソッドの戻り値をDrinkではなくObjectにしているのは、ここで使用しているプログラミング言語であるJavaの流儀に従っただけです。

リスト2●Drinkクラスのcloneメソッド

public Object clone()
{
    // // 自分と同じ値のフィールドを持つオブジェクトを生成する
    return new Drink(whiskey, soda, mizu, oyu);
}

 クラスを使う人は、最初にDrinkクラスのプロトタイプとして、たとえば、ロック、ハイボール、水割り、お湯割を表すrock、highboll、mizuwari、oyuwariというオブジェクトを作ります。後は、必要に応じてrock.clone()、highboll.clone()、mizuwari.clone()、oyuwari.clone()を呼び出せば、それぞれのオブジェクトのクローンを生成できます。

 クローンを作るということは、オブジェクト指向プログラミングにおいてとても重要なアイディアです。フィールドの数が多いクラスの場合、いちいちすべてを設定したコンストラクタを使ってオブジェクトを生成するのでは面倒です。クローンを作る方が効率的です。クラスを作る人が思いやりを込めてcloneメソッドを用意しておいてあげれば、クラスを使う人は楽ができます。Prototypeパターンの評価も、文句なく星5つです。

 これまで何度も繰り返し言ってきたことですが、オブジェクト指向プログラミングを成功させるポイントは、使う人への思いやりを込めてクラスを作ることに尽きると思います(図1[拡大表示])。オブジェクト指向プログラミングの様々なテクニックは、クラスを使いやすくするためにあると言っても過言ではないでしょう。かつて私は、日経ソフトウエア誌で「思いやり」をテーマにしたオブジェクト指向プログラミングの短期連載を書かせていただいたことがあります。継承も、カプセル化も、多態性も思いやりのためのテクニックとして説明できます。もちろん、GoFの23種類のデザインパターンも、思いやりという視点で捉えれば理解しやすく、ますます上手にOOPを実践できるようになるはずです。

 次回は、StateパターンとObserverパターンを紹介します。

矢沢久雄

グレープシティ株式会社(http://www.grapecity.com)アドバイザリースタッフ

表紙ページへ