早いもので、私の著者歴は15年ぐらいになります。いろんな記事や書籍を書いてきました。そんな中で、特に連載記事の場合は、いつも同じ書き方では読者に飽きられてしまうので、意識的に様々なパターンを使い分けています。「教科書のように堅苦しく解説する」「きさくな言葉で読者に語りかける」「師匠と弟子の問答形式にする」「図を多用した絵解きにする」...あれあれ、たったの4パターンしかないですね。誠にお恥ずかしい。そこで、今回は「クイズ形式で興味を引き付ける」という新しいパターンに挑戦させていただきます。よろしくお付き合いください。

【お役立ち度】★★★★★
●第1問:Template Methodパターンとは、どのようなものでしょう?

 まず、Template Method(雛形メソッド)という名前から、どのようなものかを想像してください。ヒントを差し上げます。これは、振る舞いに関するパターンに分類されます。つまりメソッド呼び出しに関する工夫です。

 メソッドの雛形と聞くと、処理内容のない抽象メソッドを想像されるでしょう。その考えで、合っています。でも、ただ単に抽象メソッドを使うというだけでは、パターンと呼べるほど立派なものじゃありませんね。それでは、次のヒントです。このパターンは、メソッドの機能を部分的に変更するための工夫です。たとえば、メソッドの処理内容が大きく3つの処理に分かれているとしましょう。それらの1つでも、2つでも、3つでも、必要に応じて任意に変更できるようにするには、さてどうしたらよいでしょう?

 「処理内容を3つの抽象メソッドに分けて、それらを呼び出すメソッドとすればよい」お見事! 大正解で~す。複数の抽象メソッドを呼び出すメソッド(これを「テンプレートメソッド」と呼ぶ)を作れば、処理内容を部分的に書き換えられるものとなります。なかなか素晴らしい工夫です。

 サンプルプログラムをお見せしましょう。リスト1[拡大表示]は、何らかの方法で入力された複数のデータを、何らかの方法でソートし、その結果を何らかの方法で表示するmyMethodメソッドを持つMyClassクラスです。myMethodメソッドがテンプレートメソッドであり、その処理として、データを入力するmyInputメソッド、データをソートするmySortメソッド、およびデータを表示するmyPrintメソッドが呼び出されています。

リスト1●テンプレートメソッドを持つクラスの例

public class MyClass
{
    // これがテンプレートメソッド
    public void mySort()
    {
        int[] data = new int[100];
        myInput(data); // データを入力する
        mySort(data); // データをソートする
        myPrint(data); // データを表示する
    }


    // テンプレートメソッドから呼び出される抽象メソッド
    abstract protected void myInput(int[] d);
    abstract protected void mySort(int[] d);
    abstract protected void myPrint(int[] d);
}

 データの入力は、キーボードから行うことも、マウスから行うことも、ファイルから行うことも、通信から行うこともあるでしょう。データのソートのアルゴリズムには、バブルソートを使うことも、クイックソートを使うこともあるでしょう。データの表示は、コマンドプロンプトに行うことも、ウインドウにグラフィカルに行うことも、HTMLで送信するこも、プリンタに印字することもあるでしょう。どのような手段を使うかは、MyClassクラスを継承したクラスで、3つの抽象メソッドの処理内容を実装する時点で決めればよいのです。

 ここで、追加のクイズです。3つの抽象メソッドには、mySortメソッドを利用する人への思いやりを込めた工夫がしてあります。何だかわかりますか?

 それは、メソッドの可視性にprotectedを指定していることです。protectedは、クラスを継承して使うなら見え、そうでないなら見えないという意味です。protectedを指定したことで、mySortメソッドを利用する人には、myInputメソッド、mySortメソッド、およびmyPrintメソッドが見えなくなります。したがって、これらのメソッドを誤って呼び出すことが防げます。思いやりって、いい言葉ですね。星5つの満点評価を差し上げましょう。

【お役立ち度】★★★☆☆
●第2問:Visitorパターンとは、どのようなものでしょう?

 まとめてヒントを差し上げます。Visitorパターンも、振る舞いに関するパターンに分類されます。オブジェクトに動的に機能を追加するための工夫です。Visitor(訪問者)という名前が示す通り、プログラムの実行時に訪問者がやって来て、オブジェクトに何らかの機能を追加してくれるのです。機能を追加してもらうオブジェクトの側では、訪問者を受け入れる仕掛けをしておきます。訪問者の側では、相手に自分を受け入れてもらう仕掛けをしておきます。どのような訪問者が来るのかは、オブジェクトを使う人が決めます。いかがでしょう。イメージが膨らんだでしょうか? ちょっと難しいかもしれませんね。

 サンプルプログラム(実用的でなくてごめんなさい)とともに、答えをお教えしましょう。リスト2[拡大表示]は、果実店を表すFruitShopクラスです。このクラスが訪問者を受け入れるクラスとなります。メンバには、取り扱い商品名を格納したフィールドといくつかのメソッド(ここでは・・・で省略しています)があるとします。ポイントとなるのは、訪問者を受け入れるaskVisitorメソッドです。

リスト2●訪問者を受け入れるクラス

public class FruitShop
{
    public String[] fruit = { "リンゴ", "ミカン", "バナナ" };
    ・・・
    // 訪問者を受け入れるメソッド
    public void askVisitor(SalesMan sm)
    {
        sm.setFruitShop(this);
        sm.bargainSale();
    }
}

 リスト3[拡大表示]は、果実店への訪問者を表すVisitorクラスです。この訪問者は、バナナの叩き売りのような特売セールをしてくれる販売員さんです(たとえば、フーテンの寅さんを思い浮かべてください)。setFruitShopメソッドで、フィールドshopに訪問先の果実店が格納されます。bargainSaleメソッドは、果実店のすべての取り扱い商品の名前を「~が安いよ!」と連呼します。

リスト3●訪問者を表すクラス

public class SalesMan
{
    private FruitShop shop;

    public setFruitShop(FruitShop fs)
    {
        shop = fs;
    }

    public void bargainSale()
    {
        for (int i = 0; i < shop.fruit.length; i++)
        {
            System.out.println(shop.fruit[i] + "が安いよ!");
        }
    }
}

 これで、Visitorパターンの仕掛けができました。FruitShopクラスとSalesManクラスを使う人は、それぞれのオブジェクトを生成してから、FruitShopクラスのaskVisitorメソッドの引数にSalesManクラスのオブジェクトを指定して呼び出します。askVisitorメソッドの中で、setFruitShopメソッドが呼び出されて2つのオブジェクトが結び付けられ(訪問者が訪れ)、bargainSaleメソッドが呼び出されて訪問者が仕事をします(機能が追加されます)。

 この例では、訪問者となるクラスを1種類しか作りませんでしたが、様々な機能を提供してくれる複数のクラスを用意しておくこともできます。その場合には、訪問者を表すインターフェイスを定義し、それをaskVisitorメソッドの引数のデータ型とすればよいでしょう。様々な訪問者を選んで、様々な機能を追加できるとなれば、なかなか使えそうなパターンだと感じるでしょう。

 しかし、評価は星3つと低めにさせていただきます。なぜなら、私は個人的に、オブジェクトが相互に密接に結び付けられたプログラムの構造が好きでないからです。そもそもVisitorパターンは、2つのオブジェクトを1つに結び付けることが目的なんですが...。

 次回(最終回)は、InterpreterパターンとMementoパターンを紹介します。

矢沢久雄

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

表紙ページへ