「has-a(持っている)」にも2種類あると研修で習いました。 Javaのコードではどのように書き分けますか?

こんにちは。ゆうせいです。

新人研修中に受講者から以下の質問をいただきました。

「has-a(持っている)」にも2種類あると研修で習いました。 Javaのコードではどのように書き分けますか?

今回はこの質問に答えたいと思います。

Javaのクラス設計において、集約とコンポジションの違いを理解することは、プログラムの柔軟性と堅牢性を左右する重要な要素です。これらはどちらもhas-a関係に含まれますが、オブジェクトの寿命(ライフサイクル)の管理方法に明確な違いがあります。

集約とコンポジションの定義上の違い

集約とコンポジションは、どちらも「あるクラスが別のクラスを保持している」状態を指しますが、その結びつきの強さが異なります。

集約(Aggregation)

集約は、全体と部分の関係が弱く、部分(保持される側)が全体(保持する側)から独立して存在できる関係です。

高校生向けの比喩を用いると、「教室と生徒」の関係です。教室という場所がなくなっても、生徒という存在が消滅することはありません。生徒は別の教室へ移動することも可能です。

コンポジション(Composition)

コンポジションは、全体と部分の関係が非常に強く、部分が全体と運命を共にする関係です。

比喩で言えば、「建物と部屋」の関係です。建物が壊されれば、その建物の中にあった部屋という空間も同時に消滅します。部屋だけを切り離して別の建物へ持っていくことはできません。

具体的なコードによる実装の違い

Javaにおける実装上の最大の違いは、インスタンス(オブジェクトの実体)をどこで生成し、どのように受け取るかに現れます。

集約の実装例

集約では、保持される側のオブジェクトは外部で生成され、コンストラクタなどを通じて渡されます。

class Student {
    private String name;
    Student(String name) {
        this.name = name;
    }
}

class Classroom {
    private Student student;
    // 外部で生成されたStudentを受け取る
    Classroom(Student student) {
        this.student = student;
    }
}

この場合、Classroomのインスタンスが破棄されても、引数として渡されたStudentのインスタンスは外部で参照され続ける限り生存します。

コンポジションの実装例

コンポジションでは、保持される側のオブジェクトは、保持する側のクラス内部で生成されます。

class Room {
    private String roomName;
    Room(String roomName) {
        this.roomName = roomName;
    }
}

class Building {
    private final Room room;
    // クラス内部でRoomを生成する
    Building() {
        this.room = new Room("エントランスホール");
    }
}

この場合、Buildingのインスタンスが消滅すると、内部で生成されたRoomのインスタンスも同時にガベージコレクション(メモリ解放の仕組み)の対象となり、消滅します。

メリットとデメリット

それぞれの設計手法には、事実に基づいた以下のような特徴があります。

集約のメリット・デメリット

  • メリット:オブジェクトの再利用性が高く、一つの部品(生徒)を複数の全体(教室や部活動)で共有することが容易です。
  • デメリット:外部からオブジェクトの状態が変更される可能性があり、クラスの独立性がコンポジションに比べると低くなります。

コンポジションのメリット・デメリット

  • メリット:内部のオブジェクトを完全に制御できるため、カプセル化が強固になり、予期せぬ副作用を防ぐことができます。
  • デメリット:部品が特定の全体に固執するため、柔軟な入れ替えや再利用が難しくなる傾向があります。

まとめ

集約とコンポジションは、保持されるオブジェクトの寿命を誰が責任を持つか、という点で使い分けられます。学習を進める際は、以下のステップで設計を検討してください。

  1. 二つの要素の関係が「has-a(持っている)」であることを確認する。
  2. 保持される側のオブジェクトが、保持する側なしでも存在価値があるか(集約)、あるいは運命を共にするべきか(コンポジション)を判断する。
  3. 運命を共にする場合はクラス内部でインスタンス化し、独立させる場合はコンストラクタ等で外部からインスタンスを受け取るコードを記述する。
  4. プログラムの実行時に部品を動的に入れ替える必要があるかどうかを確認し、必要であれば集約を選択する。

グループでは新人エンジニア研修のアシスタント講師を募集しています。

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。

学生時代は趣味と実益を兼ねてリゾートバイトにいそしむ。長野県白馬村に始まり、志賀高原でのスキーインストラクター、沖縄石垣島、北海道トマム。高じてオーストラリアのゴールドコーストでツアーガイドなど。現在は野菜作りにはまっている。