
知史さん

航祐君
そして、次の日…。 新人の航祐(こうすけ)君とそのチューターの知史(さとし)さんの会話です。
今日はオブジェクトコンポジションです。 継承との違いや長所、短所などについての話です。
航祐
「知史先輩、こんにちは」
知史
「やあ航祐君。 今日はオブジェクトコンポジションについて話をするんだったね。 オブジェクトコンポジションは、前にちょっと出て来たが覚えているかい」
航祐
「はい。 あるクラスに別のクラスのオブジェクトを取り込むことをオブジェクトコンポジション、そのオブジェクトに処理をまかせることを委譲と言う、とのお話でした」
航祐
「オブジェクトコンポジションなんて初めて聞きました」
知史
「航祐君は継承は知っているね」
航祐
「はい。 スーパークラスを基に機能を追加したサブクラスを作ることです」
知史
「そうだね。 継承はJava言語の機能だからJavaを学んだ人は誰でも知っている。 オブジェクトコンポジションは継承と同じように、他のクラスの力を借りて機能を果たすわけだが、単なる使い方なので、知る人ぞ知る、と言う状態なんだ」
航祐
「ああ、そうなんですか」
知史
「しかし、オブジェクトコンポジションの役割は重大で、継承より良く使われてもよいはずなんだ」
航祐
「え~、そうなんですか。 でも誰も教えてくれませんでした」
知史
「そうだね。 通常のJava教育ではJava言語の規則を教えるだけで精一杯で、とても使い方までは手が回らないんじゃないかな」
航祐
「ふ~ん」
知史
「前に触れたGof(4人組)の書いたデザインパターンの本でも、再利用可能なオブジェクト指向設計の原理としてインターフェースと並んで、オブジェクトコンポジションを多用することが挙げられているんだ」
「継承とオブジェクトコンポジションとの相違を見てみよう。 まず、親となるPerson(個人)クラスとそれを呼ぶメインプログラムを示そう。 Personクラスは氏名と年齢を保持し、要求に応じてそれを返す」
【Personクラス】

【メインプログラム】

「メインプログラムを実行させると、次のように出力される」
![]()
「このとき、Personクラスを継承して、学年を保持するStudent(学生)クラスを作ってみよう。 Studentクラスでは新たに変数「grade(学年)」を宣言しているね。 StudentクラスではPersonクラスから継承した、氏名と年齢に加えて学年も変数として持つことができるようになったわけだ」
【Studentクラス】継承を使ったコード

【メインプログラム】

「このプログラムを実行させると、次のように出力される」
![]()
「一方、継承ではなく、オブジェクトコンポジションを使ってStudentクラスを作ると、こうなる。 追加する変数はやはりgradeだ」
【Studentクラス】オブジェクトコンポジションを使ったコード

【メインプログラム】

航祐
「この(1)の部分がオブジェクトコンポジションですね」
知史
「そうだね。 航祐君、これらを比べて、気がつくことを挙げてみて」
航祐
「えーと。 オブジェクトコンポジションの方がプログラムの量が多いですね。 Studentクラスでは、まず(1)のPersonクラスの取込の部分が継承にはありません」
知史
「これは継承ではclassの宣言文でextends Personとしているから不要なのだね」
航祐
「次に、(2)のgradeの宣言は共通ですね。 (3)のコンストラクタであるStudentの部分は変数の初期化の仕方が少し異なりますが、基本的には同じです。 あれ、(4)と(5)の部分が、継承の方にはありませんね。 (6)は共通です」
知史
「(4)ではStudentクラスのgetNameメソッドの処理を行っている。 やっていることはPersonクラスのgetNameメソッドを呼び出しているだけだ。 (5)はgetAgeに対して同じことをやっている。 継承はJavaが提供している機能なので、(4)と(5)は明に書かなくてもJavaがやってくれるんだ。 しかし、オブジェクトコンポジションはプログラマーが制御しなくてはならないので(4)や(5)のようにいちいちを書かなければならない」
航祐
「ふ~ん。 ちょっと面倒ですね」
知史
「そうだね。 しかし、スーパークラスのすべてのメソッドをこのように書き直す必要はないんだ。 使うものだけを書けばよい」
航祐
「ああ、そうなんですか」
知史
「逆に継承を使うと、当面使わないものまで全部変換されてしまう。 だから継承を使ったときは、スーパークラスを変更したときには、そのサブクラスを全部調べて、変更の影響を修正する必要がある。 だから継承とコンポジションは、それぞれの特長をよく見極めて使うことが大切だ。 それぞれの得失をまとめておこう」
| クラスの継承(is-a関係) | コンポジション(has-a関係) | |
|---|---|---|
| 長所 | Javaの標準機能なので容易にコードの再利用が図れる | 2つのクラスは完全に分離している |
| 短所 | 親クラスを修正すると、その影響が子クラスに及ぶことがある | わざわざ別にインスタンスを生成しなければならない 必要なメソッドはいちいち取り込まなければならない |
航祐
「適切な使い分けは、なかなか難しそうですね」
知史
「一般にAはBの特別な種類であるときは継承関係、AはBの性質であるときにはオブジェクトコンポジションを使うとよいとされている。 StudentというのはPersonの一種だろうか、それともPersonの性質にすぎないだろうか」
航祐
「性質のような気がしますが」
知史
「そうだね。 学生でかつ社会人なんて言う人がいるケースを扱わねばならないとしたら、性質と捉えてオブジェクトコンポジションを使うべきだろうね。 しかし、もっと単純でそんなケースはないモデルを扱うなら継承しても良いかもしれない。 要はケースバイケースだ。 興味があれば識者が書いた本を参考にするとよい(注1)」
知史
「今日は大分コンポジションの肩を持ったから、次回は継承の活躍について話をしよう」
航祐
「ありがとうございました」
(注1) 例えば『UMLによるJavaオブジェクト設計 第2版』(ピーターコード著、Pearson Education)の中で著者は、オブジェクトコンポジションではなく継承を使用した方がよい条件として以下を挙げている。