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.

最初は「合成」という言葉を覚えることよりも、

車は自分ですべてをやっているのではなく、エンジンなどの部品に仕事を任せている

というイメージを持つことが大切です。

クラスは単独で使うだけではありません。

小さなクラスを作り、それぞれに仕事を任せ、それらを組み合わせて大きな仕組みを作っていく。

ここまで理解できると、オブジェクト指向の考え方が少しずつ見えてきます。

訪問数 7 回, 今日の訪問数 7回

広告

C#

Posted by hidepon