ひとつはふくすうの部分集合

デザインパターンってあるけれど、これは設計というより、内部の関数、構造体どうしのインターフェースのノウハウ・・・パターンだと考えられるんじゃないかと思う。
プログラムは大きく3つの要素・・・構造・アルゴリズム・インターフェースによって構築されると考えることができる。
いま、デザインパターンがもてはやされるのは、上記の3つの要素のうちインターフェースについてを明示的にノウハウとしてのまとめたものだからなんではないだろうか。
デザインパターンGoFの23のパターンのほかにもいろいろなものがあって、
たとえば僕なんかはNullObjectパターンなんかは多用するもののひとつだ。


プログラミングをしていると、独自のパターンを発見することがある。
もちろんそのほとんどはいわゆる再発見であり、すでに世の中に知られていて名前も付けられている。
ただし、いくつかは既知のパターンにうまくに当てはめられないものもある。
今日はそのうちのひとつ、単純だけど、非常に有用な(と僕は思ってる)パターンを紹介しよう。(長い前置きだな)


設計要件
データベースから情報を取り出す
任意のIDを与えられて、そのキーに対応する顧客名を顧客名簿データベースより取り出すインターフェースを設計する。
なおIDはユニークであり、そのIDに対応する顧客は一意に決定する。

上のような条件をあげられたときそのインターフェースは多分以下のようになるだろう。
なお以下はC++で記述する。
ケース1

String GetCustomerName(IDType id);

ケース2

bool GetCustomerName(IDType id, String& outname);

ケース1は単純に名前を返す。一方ケース2は成功したか否かを返し、その出力は引数で渡している。
データベースから顧客名をとってくる場合、もしかしたらデータベースに与えられたIDに一致するものがないかもしれない。
ゆえに成功したか否か(データベースに一致するものがあったかなかったか)を呼び出し側に必要がある。
ケース1ではStringを返している。この場合呼び出し側では以下のように空文字と比較するのが一般的だろう。

String name;
if("" != (name = data.GetCustomerName(id))){
    do_nanika(name);//顧客が見つかった
}

ただし、以下には弱点があって、それは顧客名が空文字とは一致しないという前提に立っていることだ。
(まあ普通はありえないだろうけど)顧客がAnonymousな場合に対応できない。
このケースは例が悪かったのだが、返す値に異常な値(文字列:空文字、ポインタ:NULL、ハンドル:INVALID_HANDLE_VALUE)が存在していなくては適用できないのでそういった値のない型を返り値として定義することはできない。
一方ケース2ではケース1の問題点を解決できる。返り値としては成功の可否を返し、成功したのなら引数に渡したStringに値が返ってくる。

String name;
if(data.GetCustomerName(id,name)){
	do_nanika(name);//顧客が見つかった
}

基本的にはケース2で万事解決する。
しかし2番目の引数に渡したStringは関数がtrueを返したときのみに意味を持つ。
もし関数がfalseを返したら、引数に渡したStringはどうなるのだろうか?そのまま?それとも空文字?
引数に渡した変数の値が関数の返り値によって意味を持ったり持たなかったりする。
以下のケース3はそんなケース2の気持ち悪さを解消するもう少しスマートな方法だ。

ケース3

void GetCustomerName(IDType id, std::vector<String>& out);

呼び出し側では以下のようにする。

std::vector<String> v;
GetCustomerName(id,v);
for(size_t i = i<v.size();i++){
	do_nanika(v[i]);//顧客が見つかった
}

つまり
「見つかったか見つからなかったか?、また見つかった場合はその値を返す」を、
「見つかった値の集合を返す」で置き換えてしまうのだ。
意味的にだいぶ単純になったことがわかると思う。
さらにケース3にはもうひとつ利点があり、返り値が複数になった場合にも対応できる。
例の場合では、要件として「そのIDに対応する顧客は一意に決定する」の箇所が削除されてしまったときはどうなるだろうか?たとえば与えられるIDはグループIDで、そのIDに一致する顧客は複数であるようになったらどうだろうか?
そういった場合でもケース3のようにしておけば、容易に対応できる。
0or1は0〜nの特殊な例でしかないのだ。

以上のようなやり方でインターフェースを単純化するケースは少なくないと思う。
単数を複数にして同じインターフェースで記述するという意味でcompositeパターンの逆をいくものだと考えられる。
一見相反するようだが、compositeパターンと非常に相性がいい。メンバ関数の出力を単数から複数にすることで、そのオブジェクトは複数を単数として扱うことができるようになる。