クラスを無駄にしないためのクラス管理法
オブジェクト指向の原則として、一度作成したクラスは消さずに永続的に使用します。ですから、クラスを定義するヘッダーファイルや実装ファイルはきちんと管理されるべき物であります。ところが、この管理は思ったほど簡単ではないのです。この章ではクラスの管理の難しさを示しながら、その解決の指針の一案を示してみたいと思います。テキストばかりで読み疲れるかもしれませんが、長く自分のクラスを使用したい人は必見です。
@ ヘッダーファイルと実装ファイルを分ける
ヘッダーファイルと実装ファイルは別々のフォルダに分けて管理した方が利便性が高まります。本来、オブジェクト指向とはヘッダーファイルにあるクラス(インターフェイス)宣言部だけでシステムの繋がりや役目を考える指向です。実装ファイルは、それを実現する具体的な部分に過ぎません。クラスを永続的に使用するために、インターフェイスを定義するヘッダー部は一度作ったら変えるべきではありませんが、逆に実装部はいくらでも変えてクラスの安全性と性能を向上させるべきものです。片方は固定的で、もう片方は流動的。そのような異なる性質を持つファイルを同じフォルダに入れておくよりも、別々にした方がクラスとしての保守性を高めることになります。Visual Studioのデフォルトでは、追加したクラスのヘッダーファイルと実装ファイルはプロジェクトと同じフォルダに置かれますが、正直これは嫌なデフォルト設定だと思います。まず、この習慣をやめるところからクラス管理をスタートしましょう。
A ヘッダーファイルは一元管理し、実装はライブラリ化する
作成したクラスのヘッダーファイルはパスの通った1つのフォルダにまとめ、実装ファイルはライブラリ化して、これもパスの通ったフォルダに格納する。このちょっとした作業は永続的なクラスの使用にとって必須ともいえる重要な作業になります。Visual
Studioで新しいプロジェクトを立ち上げて、既存のクラスを使おうとしたとき、皆さんはどうされていますでしょうか?「プロジェクトに追加」で必要なヘッダーファイルと実装ファイルを選択していませんか?その方法は実はクラスの永続使用を難しくする原因の1つになります。
新しいプロジェクトを立ち上げるたびに、必要なヘッダーファイルと実装ファイルを追加する方法は、ファイルが増えてくると簡単に破綻します。例えば、あるヘッダーファイルAにヘッダーファイルBとCとDが使用されている時、プロジェクトにはA、B、C、Dのヘッダーファイルおよびその実装ファイルをすべて追加しなければなりません。4つくらいなら別にいいのですが、大きなシステムとなるとヘッダーファイルと実装ファイルだけで数十〜数百ファイルにもなります。複雑に関連するクラスのヘッダーと実装をすべて追加する作業は苦痛でしかありません。実際、私もこの作業に疲れ果ててしまうために、クラスを増やしていくのが嫌になった時期がありました。
この問題は先に挙げたようにヘッダーファイルのフォルダとライブラリのフォルダそれぞれに「パスを通す」事ですっきりと解決します。実に簡単な事なんですが、その簡単さに対する見返りは素晴らしいものなんです。Visual Studio 2005の場合の設定方法を示します。まず、自分が作成したクラスのヘッダーファイルは1つのフォルダに全部まとめておきます。メニュー内の[ツール]→[オプション]で開くオプションウィンドにある「プロジェクトおよびソリューション」の中から「VC++ディレクトリ」を選択し、ディレクトリを表示するプロジェクトのリストから「インクルードファイル」を選びます。すると下に幾つかパスのリストが出てくるはずなので、そこに自分が作成したヘッダーファイルフォルダへのパスを設定します。これだけで、もう新しいプロジェクトにヘッダーファイルを追加する手間が完全に省けます。自分が作成したヘッダーファイルは、既存のヘッダーファイルであるかのように、気軽に利用できるんです。
ただ、ここが重要なんですが、そのままだとリンカエラーが出てしまいます。「外部参照が未解決」、つまり実装ファイルが見当たらないよとリンカーが文句を言ってくるんです。当然と言えば当然なのですが、ここで落とし穴が待っているんです。実は、インクルードファイルへのパスは上記のように設定できるのですが、実装ファイルへのパスはこういう設定ができないんです(色々試してみたのですが駄目でした)。つまりこのままだと、実装ファイルをプロジェクトに追加する手間は省けないのです。それじゃ上の作業の意味がありません。
そこで登場するのが「スタティックライブラリ」。必要な実装部分をスタティックライブラリとして全部まとめてしまうんです。そして、ライブラリ専用のフォルダを作成して、そこに自作のライブラリファイルを置いておきます。後は先ほどと同じようにしてライブラリフォルダへのパスを通してあげます。これで、見事にリンカエラーも無くなります。この段階で、もはやプロジェクトにヘッダーと実装ファイルを追加する必要は全く無くなってしまいます。スタティックライブラリの作成方法については、クラス構築編「ライブラリ化の勧め」をご覧下さい。
自作したライブラリを使うには、プロジェクトにライブラリへのリンクを張って、必要なヘッダーファイルのみをインクルードするだけです。これは全てプログラム上で設定できまして、次のようにします。
#pragma comment( lib, "MyLibrary.lib" )
#include <ClassA.h>
#include <ClassB.h>
この設定方法、DirectXのそれと全く同じです。DirectXが上のような方法を採用しているので当然同じくなります。この方法の方が、プロジェクトに追加する作業よりもはるかに楽ですよね。これを使って「プロジェクトに追加地獄」から解放されてください!
B クラスマニュアルは絶対に書くべし!
ヘッダーファイルもまとめ、ライブラリ化もしました。これでクラスは見違えるほど使いやすくなり、ファイルの管理もすっきりとしてきます。しかし、クラスの永続的な利用と管理にはまだ足りません。便利な機械を与えられてもそれが使えないのと同様に「作成したクラスのマニュアル」が無ければクラスは威力を発揮しないのです。使用方法を記憶に頼ってはいけません。半年前に作成したクラスなんて、とっく他人のプログラムです。説明の無いクラスは単なるパズルでして、使い方がわからずにソースを眺めて解析する時間は、非常に憂鬱で無駄なものです。でも、マニュアルがあれば、自分が作成したクラスを思い出すことができます。
問題は、マニュアルの書き方です。クラス(インターフェイス)自体の説明はそれほど難しくないと思います。クラス名、概要、メンバ関数、メンバ変数、公開か非公開化など、必要な情報を余すことなく書き込めば良いだけです。しかし、例えば20個あるクラスについてその説明を書いたとして、それを他人が見たらどう思うでしょうか?きっとその使い方が全くわからずに困惑することでしょう。クラスの説明は単なる部品の説明をしているに過ぎないからです。クラスマニュアルの本筋は、実はクラス自体の説明ではなくてその「使い方(サンプル、チュートリアル)」にあるんです。
使い方の説明は詳しくし過ぎると示すだけで大変なので、簡単なレベルに落とします。特に面倒なのが関連するクラスの組み合わせですが、これは図があるだけで非常に見通しが良くなるものです。1つの図が何千文字もの説明に勝ることなど良くあります。このことから、マニュアルは図表を挿入できるHTMLなどで書くべきであることもわかります。図表を入れて、ハイパーリンクを丁寧に張れば、クラスは輝きを増して他の人(もしくは半年後の自分自身)に受け入れられるようになります。マニュアルの良い例はMSDNでしょうね。あれ以上に詳しいプログラムのマニュアルは、世界中探してもそうそうあるものではありません。DirectXのマニュアルもすばらしいです。あのマニュアルは正に「使い方」を重点的に書いてくれています。HTMLのドキュメント製作は多少の手間がかかりますが、ホームページビルダー等の市販ソフトを用いれば、劇的に軽減されるでしょう。ちなみに、完璧なマニュアルを目指す必要はあまりありません。
マニュアルのフォーマットは人それぞれだと思いますので、こうしなければいけないという事はありません。とはいえ、何か土台が必要と思われますので、簡単なマニュアルの例を作ってみました(こちらをどうぞ)。これはDirectXのマニュアルを意識しています。項目などはDirectXのマニュアルのカテゴリーそのものを真似ています。あのカテゴリー分けは非常に素晴らしいと思います。
C マニュアルを書くタイミング
自分なりのマニュアルを書けるようになると、クラスを作るのが楽しく、また慎重になってきます。なにせ下手なクラスを作ると、そのマニュアルを書くことになりますから、むやみやたらにクラスを作らなくなります。ところで、マニュアルはいつ書いたら良いのでしょうか?この答えは無いのですが、実装とマニュアルに食い違いが起こらないように書くことが大切になります。それを踏まえた一つの案として、私は「クラスを実装する前」にマニュアルを書くことをお勧めします。クラスというのは、いきなりプログラムできるものではなくて、目の前の問題を解析しているうちに自然と発生してくるものです。問題解析の殆どはペーパーディスカッション(紙面上での議論)でして、紙の上であーだこーだと解析を続けるわけです。そして、その生成物としてクラスが抽出されてきます。ということは、実装する前にもうクラスの仕様は出来上がってしまっていることになります。であるならば、実装する前にマニュアルだって書けるわけです。
「実装し終わってからでも良いのでは?」と思うかもしれません。それも悪くはありません。ただ、実はマニュアルを書いている段階でおかしなことやちょっとしたケアレスミスに気づくことが意外と多いのです。その時に、解析段階に戻して修正すれば、実際のプログラムを汚すことはありません(何も書いていないので当然です)。もし、実装してしまっていた場合、プログラムの修正を求められます。いつでもそうですが、実装の変更はドキドキするものです。マニュアルを書くタイミングに束縛はありませんが、自分なりの原則を持って書くべきでしょうね。
以上からクラスを無駄にしないためのクラスの管理法をまとめると、次のようになります。
・ クラスのヘッダーファイルはパスの通った1つのヘッダーフォルダにまとめる。実装ファイルは別フォルダに。
・ 実装ファイルはスタティックライブラリにしてしまう。作成したライブラリはパスの通ったライブラリフォルダに置いておく。
・ 「プロジェクトに追加」の機能はヘッダーや実装ファイルに対して使わない。
・ クラス(ライブラリ)のマニュアルを必ず書く。クラスの説明だけでなく、その使用方法(サンプル、チュートリアル)も時間の許す限り作成する。
・ マニュアルは原則として実装する前に書く。
これで、クラスを忘れずに使い続けることができます。それは同時にオブジェクト指向に則ったプログラムをすることに繋がります。どうぞ皆さん、クラスを大切にしてあげてください。