Revised: May/8th/2004; Since: Feb./23rd/2003
Java のプログラムはクラスやインタフェースの集合です。要件からクラスやインタフェースを識別し、これらの間の関係を考えることが、分析/設計の第一歩です。この識別過程は繰り返し検討され、徐々に詳細化されていきます。ここでは、UML (Unified Modeling Language) というモデリング言語のクラス図というもので記述します。ここでは、Java のクラス間の関係の種類をクラス図を通してまとめておきます。
オブジェクト指向では、クラス間には継承 (inheritance) と関連 (assosiation) の関係 (relationship) があると説かれます。
継承 (inheritance) とは、コードの再利用を実現するために、スーパークラスの機能を継承してサブクラスを作成することです。サブクラスはスーパークラスの特殊なものであり、それらの間には "ia-a" 関係があります。例えば、犬は哺乳類 (A Dog is a Mammal.) であり、顧客は人 (A Customer is a Human beings.) です。このようなとき、犬は哺乳類から派生し、顧客は人から派生させることが妥当です。
関連 (assosiation) とは、クラスが部分となるクラスから構成されていることを意味し、部分と全体の間には "has-a" 関係があります。例えば、車はエンジンやハンドルを持ち (A Car has a Engine.)、コンピュータシステムは CPU やメモリを持ちます (A Computer has a CPU.)。
多くの場合、ポリモーフィズムや契約の概念に関係する継承よりも、小さな部分に分割してそれを複合する関連を採用したほうが、安定したシステムを設計できるとされています。
既に説明したとおり、 Java での継承は extends を使った、スーパークラスとサブクラスの関係になります。ここで "is-a" 関係というのは、スーパークラス型にサブクラス型を代入できることを指します。コンパイラによって、サブクラスはスーパークラスの一種であると認められるわけです。
"is-a" 関係という意味で継承を考えると、インタフェースと実装クラスも継承関係にあります。インタフェースを実装するクラス型は、実装するインタフェース型に代入可能です。例えば、クラス Dog や Car がインタフェース Countable を実装するとき、Dag is Countable であり、 Car is Countable です。
設計における文書化は非常にクリティカルな作業です。オブジェクト指向のモデル化には、 UML (Unified Modeling Language) という図を使います。UML の図には、目的に応じて 9 つの図が定義されていますが、クラス間の関係を記述するものをクラス図と呼びます。
継承 (inheritance) を広く "is-a" 関係と捕らえると、汎化 (generalization) とリアライゼーション (realization) に分けられます。Java では、汎化が継承 (extends) であり、リアライゼーションが実装 (implements) になります。
次の図は、スーパークラスとサブクラス間の汎化を指しています。クラス Dog や Cat から共通部分を抽出して、抽象クラス Mammal に汎化しています。
図:汎化 |
---|
次の図は、インタフェースを実装するリアライゼーションを示しています。クラス Product がインタフェース Comparable をリアライゼーションしています。
図:リアライゼーション |
---|
クラス間の関係はいくつかに分けて考えられます。その代表的なものが "is-a" 関係である継承であり、もう一つが "has-a" 関係の関連 (assosiation) です。関連は、特に集約 (aggregation) と呼ばれる関係があります。その中には更に強い結びつきを表すコンポジション (compositioin, composit aggregation) と呼ばれるものがあります。
クラスが他のクラスの組み合わせで構成されている関係を集約 (aggregation) と呼びます。例えば、学校は生徒を含み、注文商品は商品を持ちます。集約では、含んでいる側が消滅しても、含まれている方はなくなりません。例えば、生徒が変化しても学校は変わりませんし、注文商品が消滅しても商品は消滅しません。
import java.util.*; class School { private List students = new ArrayList (); public String getStudent (int i) { return (String)students.get (i); } }
集約のなかで、よりも強い結びつきにあるとき、コンポジションと呼ばれます。コンポジションでは、含んでいる側が消滅すると含まれている側も消滅し、一方が消滅するとオブジェクトが機能しなくなるような関係を意味します。例えば、学校がなくなると教室もなくなり、注文が消滅すれば注文商品も消滅します。
もともとは一つのクラスであったものを、モジュール分割した場合は、コンポジションの関係になることが多いでしょう。Java のコーディング上は、集約とコンポジションは区別できませんが、依存関係としては重要な違いであって、分析/設計の時点で適切に文書化することが望まれます。
Java のメンバー変数に指定されて保持されるクラスであっても、集約やコンポジションのような包含関係にない場合もあります。例えば、その機能を利用するために、メンバー変数に保持するけれども、概念として集約(包含)の関係にない場合があります。例えば、犬は飼い主に散歩をねだるかもしれず、犬の属性に飼い主を含めることは自然ですが、明らかに飼い主は犬の部分を構成するものではありません。
関連の中で、一時的な包含関係にあるものを集約と呼び、それが永続的であるとコンポジションと呼ばれます。
次の図は、集約を指しています。クラス MahjongTile (麻雀牌)を集約して DealingTile(配牌)が構築されています。
図:集約 |
---|
次の図は、コンポジションを示しています。クラス Account は Customer や Type のコンポジションとして構築されています。
図:コンポジション |
---|
次の図は、コンポジションでも集約でもない関連を示します。クラス DomainController は Domain を操作しますが、Domain と集約の関係にあるわけではありません。
図:関連 |
---|
クラスは継承と関連で構築されます。もちろん、クラス間の関係には他のものも考えられます。UML で図が用意されている残りのものである依存を紹介しておきます。
静的/構造的な関連は実践の矢印で示しますが、動的/一時的な関係は破線矢印で示し、依存 (Dependency) と呼びます。Java のコードでは、ブロック内部で生成されて消滅するような、ローカルな利用関係になります。
次の図は、依存を表します。クラス PersistentManager をクラス Order の中で利用しています。
図:依存 |
---|
図:関係 |
---|
UML では、他にもクラス間の関係を記述する規則がいくつかあります。興味のある人は、書籍やサイトなどで調べてみてください。
SEO | [PR] !uO z[y[WJ Cu | ||