野球部にカプセル化とバッテリーの共通点を説明したい

2023/08/10に公開

1.導入パート

おはようございます!

昨日に引き続き、カプセル化についての理解を深めていきたいと思います。

https://zenn.dev/articles/7ea9da82e9cdce/edit

この記事でカプセル化の説明を試みたものの、まだ理解が浅いためふわっとした説明になってしまっていました。
なので、今日こそは分かりやすく説明したいと思います!きっと説明ができればそれは理解ができているということになるとも思うので、自分のために書いていきたいと思います。

カプセル化とは何かを説明するために、カプセル化によってどんなメリットがあるのかを説明します。

カプセル化のメリットは主に下記の2つです。

  • データの隠蔽
  • インターフェースと実装の分離

難しい単語が並んでいるので、今日も野球的に考えていきましょう!

バッテリーで考えるカプセル化

カプセル化とは、データの隠蔽とインターフェースと実装の分離を目的としているということを先ほど言いましたが、それだけ言われても私にはさっぱり分かりませんでした。しかし、これを野球的に考えると、バッテリーが息を吐くように行なっていることだと気づきました。

データの隠蔽

まずデータの隠蔽について説明します。
データの隠蔽とは、クラスの内部データを外部から直接アクセスできないようにすることで、データの整合性を保つことです。
アクセスというのは、データの中身を見たり、変更したりすることのことを言います。

これは、そのままキャッチャーのサインに当てはまりますね!
敵チームや観客からサインは見れないですし、勝手に変えられたら全く配球ができません。

つまり、キャッチャーが股の間でサインを出すのは「データを隠蔽」する為と言えます。

インターフェースと実装の分離

まずはインターフェースと実装というそれぞれの言葉について説明します。

インターフェースとは、クラスの動作の使用方法を定義することです。
実装とは、その動作の内容を定義することです。

野球的に考える

まだ分かりづらいので野球に翻訳します。
インターフェースとはつまりキャッチャーがサインを出すことです。
キャッチャーはストレートとかフォークとかサインを出しますが、実際にピッチャーがどんな感覚で投げているかは分かりません。

そして、実装とは実際にピッチャーが投げることを指します。
ピッチャーは出されたサインによって投げ方を変えています。例えばストレートとフォークでは、身体のパーツをどういうタイミングで動かして、どこで力を入れて、どこで力を抜くのかといったことは異なります。

もしもインターフェースと実装が分離されていない状態を考えてみると、キャッチャーがピッチングフォームに介入するということです。ピッチャーの感覚を超えてフォームをいじられたら全体のバランスはぐちゃぐちゃになります。たまにしか来ないコーチにフォームを魔改造されて潰れていったピッチャーは数知れないですよね、、

プログラミングに戻る

脱線しましたが、またプログラミングに戻って考えたいと思います。
インターフェースと実装が分離されることで、異なるユーザーが使ってもデータが壊れないというメリットがあります。
野球の例でいうキャッチャーは、エンドユーザーやクラスの動作を使いたいエンジニアにあたり、ピッチャーに当たる人は実装の部分を作るエンジニアにあたります。

エンドユーザーや、クラスの動作を使いたいエンジニアにとっては、処理の内容を知らなくてもインターフェースを呼び出すだけでその処理が返ってくるというのは非常に使い勝手が良いです。誤操作で処理を書き換えてしまうという心配もありません。

一方でピッチャーに当たる人は、実装の部分を作るエンジニアの人などです。実装を書き換えてもインターフェースが同じであれば、そのさきのエンドユーザーなどに影響がないので、こちらの人たちにとっても都合が良いです。
その逆のインターフェースと実装が分離されていない状態とは、ストレートの投げ方の感覚を変えるたびに、「ストレート1」とか「ライジングキャノン」みたいな名前をつけて、その度にサイン(インターフェース)を変えなければいけないという状態です。これは面倒ですよね。

なんとなくイメージができたところで、これをコードで書くとどんな感じかを見ていきましょう。

コードで表現してみる

// クラスで定義することによって外部からアクセスできないようにする
class Pitch {
  constructor(stamina) {
    // この_balanceプロパティは外部から直接アクセスできないようにする(実装の詳細)
    this._stamina = stamina; // スタミナの初期化
  }

  // 直球を投げるメソッド(インターフェースの一部)
  straight() {
    console.log("直球を投げました!"); // ピッチャーの感覚の部分(実装の詳細)
    this._stamina -= 1; // スタミナを1減らす(実装の詳細)
  }

  // カーブを投げるメソッド(インターフェースの一部)
  curve() {
    console.log("カーブを投げました!"); // (実装の詳細)
    this._stamina -= 1; // スタミナを1減らす(実装の詳細)
  }

  // フォークを投げるメソッド(インターフェースの一部)
  fork() {
    console.log("フォークを投げました!"); // (実装の詳細)
    this._stamina -= 1; // スタミナを1減らす(実装の詳細)
  }
}

// 上記のコードで定義したPitchクラスを使って、ピッチャーが投げる様子をシミュレートします。
const pitcher = new Pitch(100); // スタミナを100で初期化
// インターフェイスを通じて操作(=キャッチャーがサインを出すところ)
pitcher.straight(); // 直球を投げる 
pitcher.curve();   // カーブを投げる 
pitcher.fork();    // フォークを投げる 

このコードを見てみると、ピッチャー(Pitchクラスのインスタンス)が直球、カーブ、フォークを投げる様子がシミュレートされています。
このとき、投げる球種の選択やスタミナの減少などの処理はクラス内部で完結しており、外部からは直接触れることができません。

キャッチャーの配球もコードで表せると考えると面白いですよね!

まとめ

今日は、カプセル化の概念を野球のバッテリーに例えて説明しました。
要点を3つのポイントでおさらいします。

  • カプセル化:オブジェクト指向プログラミングの重要な概念で、データの隠蔽とインターフェースと実装の分離を実現するメリットがある。
  • データの隠蔽:クラスの内部データを外部から直接アクセスできないようにし、データの整合性を保つこと。野球でいうと、キャッチャーのサインのようなものです。
  • インターフェースと実装の分離:クラスの使用方法(インターフェース)と動作の内容(実装)を分けること。野球でいうと、キャッチャーのサインとピッチャーの投げ方のようなものです。

この記事がカプセル化の理解に役立ったら嬉しいです。
もし気に入っていただけたら、いいねやフォローをお願いします!

それでは今日も学習をスタートします!

Discussion