プログラミングにおける"オブジェクト指向"とは？主要な概念についても解説

<br>

## ■ はじめに
<br>

`オブジェクト指向`という言葉をご存知でしょうか？
Javaはこの「オブジェクト指向」を採用している言語です。
このオブジェクト指向というのはプログラミングにおいて **データ** と **その操作** を
1つの「**オブジェクト**」として扱うことで、複雑なシステムを整理して理解しやすくするといった考え方です。

今回はそのオブジェクト指向の基本的な概念と、Javaでの実装例を用いて理解を深めていきましょう。

## ■ 目次
<br>

1. [オブジェクト指向とは](#1-オブジェクト指向とは)
2. [カプセル化](#2-カプセル化)
3. [継承](#3-継承)
4. [ポリモーフィズム](#4-ポリモーフィズム)
5. [まとめ](#5-まとめ)

## 1. オブジェクト指向とは

<br>

オブジェクト指向とはプログラムを「**オブジェクト**」という単位で組み立てていく方法のことです。
オブジェクトはデータ（またはフィールド）とその操作（メソッド）を一つにまとめたもので、
現実世界のモノや概念をプログラム上で表現しています。

ここでは例として「犬」というオブジェクトで考えてみましょう。
このオブジェクトには「名前」や「年齢」といったデータを持たせます。
更に「吠える」や「座る」といった動作を持たせることができます。

オブジェクト：名前、年齢
データ：吠える、座る

```java
class Dog {
    String name;
    int age;

    void bark() {
        System.out.println(name + "が吠える");
    }
    
    void sitDown() {
        System.out.println(name + "は座る");
    }
}
```

また、オブジェクト指向の主要な概念は3つあり、
- カプセル化
- 継承
- ポリモーフィズム

となります。

## 2. カプセル化
<br>

カプセル化とは、オブジェクトのデータを外部から直接アクセスできないようにする考え方のことです。
カプセルに閉じ込めることでデータをオブジェクトの中で「隠蔽」し、データへのアクセスや操作は専用のメソッド（Getter[^1]やSetter[^2]など）を通して行います。

カプセル化することにより、プログラムの各部分が相互に干渉し合わずに変更や修正が可能になります。

```java
class Dog {
    private String name; //カプセル化（privateで宣言されている）
    private int age; //カプセル化（privateで宣言されている）

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

```

上記ではnameとageは`private`として定義されているため、外部のクラスからこの変数に直接アクセスすることはできません。
外部のクラスからnameとageを取得したい場合には、publicのgetNameやgetAgeメソッドを使うことでそれぞれの値を取得することができます。

## 3. 継承

<br>

既存のクラス（親クラス）から新しく作成するクラス（子クラス）を作成する仕組みを**継承**と呼びます。
継承した子クラスは親クラスのすべてのフィールドやメソッドを引き継ぎ、必要に応じて追加や上書きができます。

```java
class Animal {
    String name;

    void eat() {
        System.out.println(name + "は食べている");
    }
}

class Dog extends Animal {
    void bark() {
        System.out.println(name + "は吠える");
    }
}
```

`Dog`クラスに継承を表す`extends`がついており、以降に記載されている`Animal`クラスを継承しているということを表しています。

:::note
class 継承先クラス名 extends 継承元クラス名
:::

`Animal`クラスを継承したことにより、Dogクラスはnameフィールドや`Animal`クラスにしかないeatメソッドをそのまま利用することができ、
ここでは`Dog`クラスに`bark`という新しいメソッドを追加しています。

## 4. ポリモーフィズム

<br>

ポリモーフィズム（多態性）は「同じメソッドでもオブジェクトの型に応じて、異なる振る舞いをすること」です。これにより、同じコードでも異なるクラスのオブジェクトに対して対応できるようになります。

```java
class Animal {
    void cry() {
        System.out.println("動物が鳴く");
    }
}

class Dog extends Animal {
    void cry() {
        System.out.println("犬が鳴く");
    }
}

class Cat extends Animal {
    void cry() {
        System.out.println("猫が鳴く");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myDog = new Dog();
        Animal myCat = new Cat();

        myDog.cry(); // 「犬が鳴く」と出力される
        myCat.cry(); // 「猫が鳴く」と出力される
    }
}
```

上記では親クラスの型を使って、子クラスのオブジェクトを扱おうとしています。
`Animal myDog = new Dog();`
では親の型を使ってインスタンスを生成していますが、
`myDog.cry();`
で呼ばれるのはDogクラスのcryメソッドであるため、「犬が鳴く」と出力されます。

このように、Animalクラスを継承したDogやCatクラスがそれぞれ独自のcryメソッドを持っていても
同じcryメソッドが異なる動物のオブジェクトによって違う結果を出すのが、**ポリモーフィズム**の特徴です。

親クラスの参照型で子クラスのオブジェクトを操作した結果として
子クラスで上書き（オーバーライド[^3]）されたメソッドが呼ばれるという動作を指します。

## 5. まとめ

<br>

- オブジェクト
    - データと操作を1つの「オブジェクト」として扱う考え方
- オブジェクト
    - フィールド（データ）とメソッド（操作）が含まれる
- カプセル化
    - データを隠蔽（private）し、専用メソッドを通してアクセスすること
    - プログラムの保守性が向上する
- 継承
    - 親クラスの機能を子クラスに引き継ぐことで、コードの再利用性が高まる
- ポリモーフィズム
    - 同じメソッドが異なるクラスで異なる動作をすること

[^1]:private になっているフィールド変数を取得するためのメソッド
[^2]:private になっているフィールド変数を設定するためのメソッド
[^3]:親クラスで定義されたメソッドを子クラスで再定義し、子クラス独自の動作に置き換えること