生成に関するパターン
 
 やっぱ最初は「生成」についてからです。
 
 Factory Method
 
 「インスタンスを作成する関数」を仮想関数にするというもの。他のインスタンスを作成したり、いろいろな処理をしたい場合には、派生クラスを作成してオーバーライドすればOK。
 これって、CWinApp::InitInstance()がそのまんまでない? AppWizardでアプリ作ると、ダイアログとかSDIとかで違う実装としてオーバーライドするわけだから。しかもCWinApp::m_pMainWndCWnd *型、つまりCDialogCFrameWnd抽象基底クラス。まさにって感じですね。
 
 Prototype
 
 クラスそのものに自分のクラスのインスタンスを作成する機能を持たせるパターン。クラスのプロパティが多くて複雑だったり、クラスがいっぱいあるときには便利ですね。
 雰囲気的にはIUnknown::AddRef()がこれに近いと思う。
 
 Factory Method と Prototype
 
 一応このふたつが競合する形になると思います。つまり、どっちを取るか。
 生成したいクラスがすでに存在するなら、PrototypeClone()を埋め込めないので不可です。埋め込めるのなら、とりあえず埋め込んでおく、ということもいいでしょう。
 もし、生成したインスタンスを所持するクラスを変えられるのなら、その中にFactory Methodを埋め込むのがいいでしょう。自分自身でインスタンスを持つわけですから、比較的応用が利きます。
 
 このふたつは完全に競合するとは限りません。たとえば、Prototypeも、最初は普通にインスタンスを作成しなければなりません(本ではこれをprototypeと表現しています(ややこしい……))が、この最初のインスタンスをFactory Methodを用いて作成するのもひとつの手です。
 Factory Methodを使ってインスタンスを作成したら、それをPrototypeを用いて複製を作っていく、という形もアリです。このように、デザインパターンは「ここにはこのパターン!」と割り切れる部分はあまりないと言えるでしょう。
 
 Abstract Factory
 
 派生クラスを変えることで、作成するクラスのセットを動的に変更するパターンです。
 
 本ではFactory MethodAbstract Factoryの違いについて難しく書いてあるように感じられます。一応僕なりに考えた結果、Factory Methodは「もともとインスタンスを持つことになっていたクラスに生成を行う仮想関数を持たせる」ことで、Abstract Factoryは「インスタンスを作るクラスをわざわざ作る」ということだと判断しました。
 でもそうなると「Abstract FactoryFactory Methodで実現する」というのはなんか矛盾してる気もします。たぶん、「まったく別のクラスを作ってもいいし、インスタンスを持つクラスとFactory クラスが一緒でもいい」ってことなんじゃないかなーと。
 
 また、Abstract FactoryPrototypeを用いても実現できます。カスタマイズできるツールボックスで、デフォルトからの複製などを作成する場合などに使えると思います。
 もちろん、PrototypeFactory Methodを組み合わせることもできるので、これらみっつをすべて組み合わせることだってできるわけです。つまり、ここでの区別は「視点」だと思います。あまり気にせず、感覚的に使っても悪くないんじゃないかなと。
 
 Builder
 
 これは他とはかなり毛色が違います。まず、Builderには「生成に関して必要なステップとしてのメンバ関数」を持たせます。つまり生成時に必ず呼び出すメンバ関数を抽象基底クラスの仮想関数として持たせ、継承先で実装させるわけです。
 Directorはこれを順に呼び出します。これだけです。つまり「生成ステップ上のメンバ関数を決めて、それをDirectorで一律に呼び出す」というだけのことです。
 
 Directorはなんかあんまり役に立っていません。かなりつまんない役回りです。たとえば、Directorは「ボタンを押す」くらいの役割です。ジュースの自動販売機の前に立ったら「ボタンを押す」、アイスの自動販売機の前に立ったら「ボタンを押す」、タバコの自動販売機の前に立ったら「ボタンを押す」、ただそれだけの役目です。
 Builderは、この例での各自動販売機にあたります。で、これらの前後にいる人が「クライアント」ということになります。クライアントはDirectorBuilderも自分で管理しますから、前処理も後処理も自由自在ということになります。それこそ、前述の例でどんなものでもDirectorに渡してボタンを押してもらうことだってできるわけです。
 
 というわけで、このパターンは無茶苦茶フレキシブルです。クライアントだけの生成構造に、ちょっとだけ形式化してコードを見やすくしたり動的化したりしたいばあいにこのパターンを使うといい感じになるでしょう。と言っても、もしかしたら余計分かりにくくなるかもしれませんが……。
 
 Singleton
 
 インスタンスの作成をひとつの関数でまかなうことで、インスタンスの数を管理するパターンです。
 比較的楽なのはFactory Methodでしょう。CWinApp::InitInstance()の例のように、Factory Methodを持つクラスがひとつしか存在しない場合には、管理が楽になります。
 そうでない場合や他のパターンでは、グローバルなデータとしてインスタンスの数を数える方法があります。グローバルデータの管理方法としては、ただのグローバル変数、クラスのスタティック変数、関数内のスタティック変数などの他、ウィンドウズならメモリマップトファイルや同期オブジェクト(セマフォやミューテックス)などで実現できます。これらはそれぞれメリットとデメリットがあるので、それらを踏まえて使用すべき方法を選んでください。
 
 削除について
 
 生成についてはいろいろと書かれていますが、実は「削除」が結構大きな問題です。インスタンスはどうやって生成されたか分かりません。newなのかmalloc()なのか、CoTaskMemAlloc()なのかCoCreateInstance()なのか。そしてこれらはすべてポインタとして管理されてしまいます。
 
 本当の理想はoperator newoperator deleteのオーバーロードです。この中に特殊な初期化を封じ込めてしまえば、削除に関して悩むことはないでしょう。ですが、APIなどを使用する場合には、元々存在する構造体等を使用するわけですから、そうもいきません。
 もうひとつの理想はスマートポインタを使用することです。「デリーターとして働く関数オブジェクトを用いたスマートポインタ(近日公開予定(笑))」を使用すると、破棄を適切な方法で処理できます。これは比較的実用性のある方法ですが、基底クラスと派生クラスの関係をうまく継なげない場合があり、すべてに使い回せるというわけにはいかないと思います。
 
 とりあえず今のところは、生成したクラスが破棄も行うことをお勧めします。
 Abstract Factoryなら、生成したインスタンスを返した時と同じように、使用済みのインスタンスを受け取って破棄するメンバ関数を作成すれば、かなり安全に処理できるでしょう。
 Factory Methodも同様です。インスタンスを所持しているのなら、破棄も当然行うでしょう。「Factory Methodだけオーバーライドして、破棄を行うメンバ関数は基底クラスのもの」ということがないように、破棄を行うメンバ関数は純粋仮想関数としておくのもひとつの手でしょう。
 Prototypeの場合には、IUnknownの例のように自分のクラスで生成も破棄もできるような形が理想的でしょう。
 Builderはインスタンスの状況をかなり具体的に知っていると思います。破棄を生成時と同じように行ってもいいですし、個別に普通に破棄しても構わないでしょう。
 Singletonの場合には、インスタンスを一元管理した方がいいでしょう。つまり「インスタンスの数」の管理と同時に「インスタンスの生成と破棄」も管理します。そうでないと、実行中に数が合わなくなってしまうと思います。
 
 もし「生成されるプロダクトクラス」も自分で作成したものなら、「生成するファクトリークラス(Abstract Factoryなど)へのポインタ」を渡してしまうことも手です。生成したインスタンスにファクトリー側インスタンスのthisポインタを渡すということです。
 インスタンスは破棄される時、自分を作成したクラスのインスタンスから破棄を行うメンバ関数を呼び出して適切に自分を解放することができます。これもパターンのひとつです(現在調査中(笑))。
 
 「生成に関するパターン」を使用するということはおそらく、様々なクラス、多種多様なインスタンスを扱う必要があるということだと思います。そのため、メモリリークはシステムに大きなダメージを与えかねません。生成と同様、破棄もパターン化して、見やすく分かりやすい形にしましょう。実際、メモリリークが発見されてから、「パターンを用いることの効用」について納得させられることになると思います。
 
 生成についてのまとめ
 
 まず、作成するインスタンスがあまり多くなかったり、クラスの種類が少なかったりする場合には、「再利用」について考える方がいいでしょう。この場合、Factory MethodBuilderが有効になります。これらを各プロジェクトで使い回すことで、コードを見やすくし、保守を楽にできるでしょう。
 クラスの種類が多かったりインスタンスを大量に作成する場合には、Factory MethodPrototypeを使用することになると思います。この場合、生成したインスタンスの管理、そして破棄なども含めて、全体的な構造を考える必要が出てくると思います。様々な要因を踏まえて、どういったパターンを使うべきか、決めるべきでしょう。
 まずは前者を意識して、汎用的なパターンの使い方を目指してください。
 
(C)KAB-studio 1999 ALL RIGHTS RESERVED.