Revised: Dec./14th/2003; Since: Feb./18th/2003
オブジェクトやクラスが何であるのかは説明しました。では、こんなアプリケーションを作りたいと思ったときに、どんなオブジェクトの集合として作ればよいのでしょうか。これを習得するためには、アプリケーションの設計の概念にまで立ち入る必要があります。ここでもう一度、概念的な説明に立ち戻りましょう。ここで紹介する事柄を含めて、オブジェクト指向なのです。
まず、どんなアプリケーションにしたいのか、要求があります。この要求を文書に起こしたものを要件定義書と呼びます。要件定義書から、名詞を抜き出します。それらの中から、同じようなものを整理して、実体(エンティティ)を抽出します。これがクラスとその属性になります。
例えば、銀行のATMのアプリケーションを考えると、口座がクラスになり、口座名義、口座番号、残高などは口座の属性になります。
このとき、クラスの機能は制限するように、細かく分けるようにしたほうが得策です。一つのオブジェクトが、一つの機能だけに責任を持つようにします。これを、粒度が高いと表現します。粒度の高いオブジェクトであれば、再利用しやすく、機能拡張にも柔軟です。
オブジェクトはクラスから具体的に生成する個物です。逆に言うと、クラスはオブジェクトを一般化したものだといえます。鶏卵論法で、どっちが先かを決める決定的な論拠はありませんが、オブジェクト指向では、「最初にクラスありき」と考えます。オブジェクトの状態を表す属性(データ)はクラスの変数になります。オブジェクトはデータを抽象化したものだといえます。RDB のデータベース設計と似ていることに注目してください。
オブジェクトの属性は、他のオブジェクトによって変更を受けるはずです。「によって」と書きましたが、正確には「他のオブジェクトの依頼を受けて」となります。他のオブジェクトの依頼を受けて、オブジェクトの属性は様々な振る舞いをします。オブジェクトの振る舞いを記述するのが、メソッドになります。要件定義書の中では動詞として切り出されます。
要件定義書の中で、クラスは名詞であり、オブジェクトはその特殊化された実体です。例えば、銀行口座はクラスであり、「菅井学の口座」はオブジェクトです。例えば、トランプのカードはクラスであり、「クラブのA」などはオブジェクトです。
クラスから具体的なオブジェクトを生成する値である属性も名詞です。銀行口座から「菅井学の口座」を生成するためには、属性に「菅井学」や「千円」などの具体的な値を与える必要があります。トランプから「クラブのA」を生成するためには、属性に「クラブ」や「A」を代入する必要があります。
オブジェクトの振る舞いであるメソッドは動詞です。例えば、「口座名義を照会する」、「残高を照会する」、「預け入れる」、「マークを照会する」、「数字を照会する」などになります。
以上を踏まえると、例えば、何かを生成するオブジェクトがあるとき、クラス名は「Xxxジェネレーター」や「Xxxプロデューサ」、生成するメソッド名は「xxxジェネレート」、「xxxプロデュース」になるでしょう。
一般に、要件からクラスを切り出すのは難しい作業です。設計段階で、繰り返し繰り返し、クラスの切り出しを見直す必要があります。それでも、開発実施段階になって、変更が必要となることがあります。クラスの追加/削除/変更は容易ですので、これらは積極的に行われます。一般に、オブジェクト指向開発では、設計段階のクラスの切り出しは繰り返し見直され、設計/開発/テストの流れも繰り返されます。この繰り返しの中で、ユーザの要求を反映させる要件を確定し、それを確実に提供できるアプリケーションの納品を目指すわけです。
繰り返しになりますが、オブジェクトはクラスから生成します。クラスは、変数とメソッドを組み合わせたものです。変数にオブジェクトの状態を表す値を代入することでオブジェクトを生成します。これをインスタンス化と呼びました。メソッドはオブジェクトの振る舞いを記述します。オブジェクトが他のオブジェクトにメッセージを送ると、メッセージが送られたオブジェクトは、自分のメソッドを実行して自分の状態を変更し、メッセージを送ったオブジェクトに何らかの応答を返します。ここでは、オブジェクトの状態が、メッセージを送られることによって変化します。
預金口座クラスは、口座名義や残高などの変数を持つでしょう。メソッドとして、口座名や残高を照会するものや、「預け入れる」、「引き出す」などを持つでしょう。口座名義や残高に具体的な値を代入することで、具体的な口座が生成されます。これがオブジェクトです。オブジェクトに対して、預け入れるというメソッドを発行すれば、その口座の残高の値が増えることになります。
DB にアクセスするオブジェクトであれば、データベース名やデータベースを操作するモジュール名を持つでしょう。メソッドには、データベースに対して命令を発行するものや、データベースから値を取り出すものが用意されているいるでしょう。
基本的に、オブジェクトの状態(変数)を、他のオブジェクトが、メッセージ(メソッド呼び出し)を介さないで、直接変更することは好ましいことではありません。そのため、属性にはアクセス制限をかけて、外部からは、直接アクセスできないようにしておくことが望まれます。
オブジェクトの属性とメソッドは、全て非公開としておき、最低限度のメソッドだけを公開します。外部のオブジェクトは、ごく限られた公開されているメソッドだけを介して、属性を変更することが許されるようにしておきます。このような設計をカプセル化と呼びます。
オブジェクト指向では、全ての属性とメソッドを隠蔽することが原則です。全て隠蔽されたオブジェクトは孤立して利用価値がありませんので、最低限度だけを公開します。開発中に必要が生じたら、少しずつ公開されたメソッドを追加するようにします。オブジェクト指向の開発は、一連の開発手順を繰り返すことになります。このような開発プロセスを、反復型 (iterative process) と呼びます。
カプセル化のメリットは、デバッグと保守/変更が容易になることです。例えば、ある属性に不正な値が代入されているとき、全てのコードが自由にアクセスできる場合には、全てのコードが疑惑の対象になります。しかし、ごく限られたメソッドでだけ変更可能である場合は、当該クラス内と、公開されたメソッドを使っている一部のコードだけをチェックすれば良いことになります。あるいは、公開されているメソッドに入力値の妥当性チェックのロジックを噛ませてやることもできます。また、例えば、クラスの内部のコードを変更したいとき、隠蔽されたデータ構造やメソッドを変更する分には、外部のコードへの影響を考慮する必要はありません。外部に公開されたメソッドの引数と戻り値の型が同じである限り、そのクラスを利用する外部のコードには、影響を全く与えないからです。
実際にアプリケーションを開発するには、開発するアプリケーションの機能には何が必要か、どの様なクラスで構成するのか、クラスの属性やメソッドに何を与えるのか、どのメソッドを公開するのか、オブジェクト同士がどのようにメッセージを送りあうのか、どんなマシン構成で実行するのかなどを決定する必要があります。こういったアプリケーションの仕様の文書化(ドキュメンテーション)は、開発においては極めてクリティカルです。
オブジェクト指向では、設計の文書化は UML (Unified Modeling Language) と呼ばれる図で記述します。ユーザ、設計者、開発作業者ら、開発に携わる全ての人が同じ成果物を想定していることが理想です。誰かが「こんなはずじゃなかった・・・」と言い出したら、スタート地点に立ち戻る必要があります。クオリティやコスト・リカバリが著しく低い場合は、プロジェクトの放棄、チームの解散も含めて検討する必要があります。
本稿では、設計や開発手法、プロジェクト管理などについては扱いません。プログラミングに必要なスキルを、具体的なコードと実行例に基づいて解説します。