C#の「合成」を車で理解しよう ― クラスの中に別のクラスを持たせる
C#でクラスを勉強していると、少しずつ「複数のクラスを組み合わせる」という考え方が出てきます。
その代表的なものが**合成(Composition:コンポジション)**です。
「合成」と聞くと難しそうですが、考え方そのものはそれほど難しくありません。
今回は、身近な車を例に考えてみましょう。
車は1つのものだけでできていない
普段、私たちは「車」を1つのものとして見ています。
しかし、実際の車をよく考えてみると、
- エンジン
- タイヤ
- ハンドル
- ブレーキ
- シート
など、たくさんの部品を組み合わせて作られています。
つまり、
車は、いろいろな部品を「持っている」
と考えることができます。
プログラムの世界でも同じように考えることができます。
たとえば、
class Car
{
}
という車のクラスを作ったとします。
そして別に、
class Engine
{
}
というエンジンのクラスを作ります。
この2つを組み合わせて、
Carの中にEngineを持たせる
という設計ができます。
これが合成の基本的な考え方です。
まずEngineクラスを作ってみよう
最初に、エンジンを表すクラスを作ります。

class Engine
{
public void Start()
{
Console.WriteLine("エンジンが始動しました");
}
public void Stop()
{
Console.WriteLine("エンジンが停止しました");
}
}
Engineクラスには、
Start()
と
Stop()
という2つのメソッドがあります。
Start()を呼び出すとエンジンが始動し、
Stop()を呼び出すとエンジンが停止する、
というイメージです。
ここで重要なのは、エンジンの仕事はEngineクラスに任せているということです。
CarクラスにEngineを持たせる
次に車を表すCarクラスを作ります。

class Car
{
private Engine engine = new Engine();
public void Start()
{
Console.WriteLine("車を動かします");
engine.Start();
}
public void Stop()
{
engine.Stop();
Console.WriteLine("車を止めました");
}
}
注目してほしいのは、ここです。
private Engine engine = new Engine();
Carクラスの中でEngineのインスタンスを作っています。
イメージとしては、
Car
└─ Engine

です。
つまり、
車の中にエンジンがある
という現実世界の関係を、そのままプログラムでも表現しています。
これが**合成(Composition)**です。
Mainメソッドから車を動かしてみよう
それでは、実際に車を作って動かしてみます。
class Program
{
static void Main()
{
var car = new Car();
car.Start();
car.Stop();
}
}
まず、
var car = new Car();
で車を1台作っています。
そして、
car.Start();
を実行します。
すると、CarクラスのStart()が呼ばれます。
その中では、
engine.Start();
が実行されます。
つまり、
Program
↓
Car
↓
Engine
という順番で仕事が渡されていきます。
プログラム全体を確認しよう
ここまでのコードを1つにまとめると、次のようになります。
using System;
class Engine
{
public void Start()
{
Console.WriteLine("エンジンが始動しました");
}
public void Stop()
{
Console.WriteLine("エンジンが停止しました");
}
}
class Car
{
private Engine engine = new Engine();
public void Start()
{
Console.WriteLine("車を動かします");
engine.Start();
}
public void Stop()
{
engine.Stop();
Console.WriteLine("車を止めました");
}
}
class Program
{
static void Main()
{
var car = new Car();
car.Start();
car.Stop();
}
}
実行すると、次のように表示されます。
車を動かします
エンジンが始動しました
エンジンが停止しました
車を止めました
Carが全部の仕事をする必要はない
ここが、クラスを使ったプログラムを理解するうえで大切なところです。
もしCarクラスが、
- エンジンの処理
- タイヤの処理
- ブレーキの処理
- ハンドルの処理
をすべて自分で担当したらどうなるでしょうか。
Carクラスはどんどん大きくなってしまいます。
そこで、
Car
├─ Engine
├─ Tire
├─ Brake
└─ SteeringWheel
のように、それぞれの部品を別のクラスとして考えます。
エンジンのことはEngineに任せる。
タイヤのことはTireに任せる。
ブレーキのことはBrakeに任せる。
そしてCarは、それらを組み合わせて車として動かす役割を担当します。
これが合成を使う大きな理由です。
「has-a」の関係と覚えよう
合成を理解するときに便利なのが、has-a(持っている)という考え方です。
今回の例なら、
Car has an Engine.
です。
日本語なら、
車はエンジンを持っている。
となります。
これは自然ですよね。
同じように、
Car has Tires.
なら、
車はタイヤを持っている。
となります。
「AはBを持っている」という関係なら、合成を使って表現できないか考えてみるとよいでしょう。
継承とは何が違うの?
クラスを勉強していると「継承」も登場します。
合成と継承は、考え方が違います。
継承はis-aの関係です。
たとえば、
車は乗り物である
なら、
Car is a Vehicle.
と考えることができます。
一方、
車はエンジンを持っている
は、
Car has an Engine.
です。
こちらは合成です。
整理すると、
継承
Car is-a Vehicle
車は「乗り物」である
合成
Car has-a Engine
車は「エンジン」を持っている
となります。

「である」なのか、「持っている」なのかを見ると違いが分かりやすくなります。
現実世界をそのまま考えてみよう
合成を理解するとき、最初から難しいプログラム用語で考える必要はありません。
まず現実世界を見てください。
車なら、
車
│
┌────┼────┐
↓ ↓ ↓
エンジン タイヤ ブレーキ
のように、いくつもの部品からできています。
プログラムでも、
class Car
{
private Engine engine;
private Tire tire;
private Brake brake;
}
のように表現できます。
つまり合成とは、
大きなものを、役割を持った小さな部品の組み合わせとして作る考え方
だと考えると分かりやすいでしょう。
合成を使うと何がうれしいの?
合成を使うメリットの1つは、それぞれのクラスが自分の仕事に集中できることです。
Engineはエンジンの仕事を担当します。
Brakeはブレーキの仕事を担当します。
Carは、それらを組み合わせて車として動かします。
人間の世界でも、
1人が全部やる
より、
それぞれの担当者が自分の仕事をして、全体として1つの仕事を完成させる
ほうが整理しやすいですよね。
クラスも同じように考えることができます。
まとめ
今回覚えてほしいポイントは、まず次の3つです。
1. クラスの中に別のクラスのオブジェクトを持たせることができる
private Engine engine = new Engine();
2. このように部品を組み合わせて大きなものを作る考え方を「合成」と呼ぶ
Car
└─ Engine
3. 合成は「has-a」の関係で考えると分かりやすい
車はエンジンを持っている
Car has an Engine.
最初は「合成」という言葉を覚えることよりも、
車は自分ですべてをやっているのではなく、エンジンなどの部品に仕事を任せている
というイメージを持つことが大切です。
クラスは単独で使うだけではありません。
小さなクラスを作り、それぞれに仕事を任せ、それらを組み合わせて大きな仕組みを作っていく。
ここまで理解できると、オブジェクト指向の考え方が少しずつ見えてきます。








ディスカッション
コメント一覧
まだ、コメントがありません