見出し画像

#2 (続)オブジェクト指向って何だっけ

オブジェクト指向に関して自分なり理解を記事にしています。
前回記事ではオブジェクト指向以前の書き方・考え方をサンプルを使って説明してみました。
今回からオブジェクト指向に踏み込んでいきます。

<前回作成したサンプルコード>
「犬、猫、象にそれぞれ鳴き声をあげてもらう。1000メートル走してもらい一位を表示する」プログラム

// 動物データ
class AnimalData {
  String name = "";
  String cry = "";
  int speed = 0;
}

void main() {
  // 犬のデータ
  AnimalData dogData = AnimalData();
  dogData.name = "犬";
  dogData.cry = "わん";
  dogData.speed = 5;
  // 猫のデータ
  AnimalData catData = AnimalData();
  catData.name = "猫";
  catData.cry = "にゃん";
  catData.speed = 4;
  // 象のデータ
  AnimalData elephantData = AnimalData();
  elephantData.name = "象";
  elephantData.cry = "ぱおん";
  elephantData.speed = 20;
  // 鳥のデータ
  AnimalData birdData = AnimalData();
  birdData.name = "鳥";
  birdData.cry = "ぴぃ";
  birdData.speed = 100;
  // 動物のデータをリストに格納していく
  List<AnimalData> animals = [];
  animals.add(dogData);
  animals.add(catData);
  animals.add(elephantData);
  animals.add(birdData);
  
  // ----------------------------------------------
  // 動物に鳴き声を出力する
  // ----------------------------------------------
  for (int i = 0; i < animals.length; i++) {
    animalCry(animals[i].name, animals[i].cry);  
  }
  
  // ----------------------------------------------
  // 動物に1000メートル走してもらい一番を決める
  // ----------------------------------------------
  const int runDistance = 1000;
  String fastestAnimalName = "";
  double fastestTime = double.maxFinite;
  for (int i = 0; i < animals.length; i++) {
    double runTime = calcRunTime(runDistance, animals[i].speed);
    if (runTime < fastestTime) {
      fastestTime = runTime;
      fastestAnimalName = animals[i].name;
    }
  }
  print("1000メートル走で最も早いのは${fastestAnimalName}です。");
}

// 鳴き声を出力する関数
void animalCry(String name, String cry) {
  print("${name}の鳴き声は「${cry}」です。");
}

// 距離ごとのタイムを計算する関数
double calcRunTime(int runDistance, int speed) {
  return runDistance / speed;
}

引き続き、ChatGPTから得た解説に対して補足する形で進めていきます。


2.概要部分(オブジェクト指向以降)

オブジェクト指向プログラミングは、プログラムを「オブジェクト」という基本単位で考える方法です。オブジェクトとは、データ(プロパティ)とそれを操作する手続き(メソッド)を一つにまとめたものです。

ChatGPTより

ChatGPTから得たオブジェクト指向に関する説明の概要部分です。
前回のサンプルコードを見ると、動物のデータをmain関数が取得した上で処理しています。main関数が間に挟まっているので、確かにデータと手続きが一つにまとまっていないですね。

今回の記事では、データと手続きにまとめた形で実装していきます。
※「継承」「カプセル化」「多態性」は後の記事で書くのであえて使用せず進めます。

2-0.オブジェクトとは何か再度考える

オブジェクトとは、データ(プロパティ)とそれを操作する手続き(メソッド)を一つにまとめたものです。

この説明は正しいと思いますが、個人的にはオブジェクトは「人間が理解しやすいよう現実に置き換えることが出来る単位」と言った方がしっくりきています。

例えば
・「人間」「犬」「猫」といった生き物
・「机」「ボール」「掃除機」といった道具
・「画面」「ボタン」「スクロールバー」といったシステムの要素
・「追加処理」「更新処理」「完了通知」といった実体をもたない概念
・「受信者」「通知者」「観測者」といった役割
などなど
こうした現実にある実体あるなし問わず存在するモノを「オブジェクト」とすることが出来ます。

現実にあるモノなので「そのオブジェクトが何をしているか、その役割」が人間にはより分かり易いことがメリットです。
システムの規模が大きくなる程、この「分かり易さ」が重要です。

こうなると、オブジェクトが「データとメソッド一つにまとめたもの」となるのは当然といえます。
例えば、猫を表すには名前・体重・色をもちますし、鳴く・走る・寝るといった動きもします。一つにまとまっていないと表せないのです。

2-1.オブジェクト化を検討する

「犬、猫、象にそれぞれ鳴き声をあげてもらう。1000メートル走してもらい一位を表示する」
犬、猫、象は分かり易くオブジェクト化出来そうですね。他にも候補がありますが、今の段階だと説明が更にややこしくなりそうです。
一旦はここまでにします。

2-2.データとメソッド化を検討する

各動物のオブジェクトに必要なデータとメソッドを考えます。
それぞれに違和感がないデータとメソッドは
・データ
 名前、鳴き声、速度
・メソッド
 鳴く、走る
でしょうか。これで実装してみます。

2-3.実装する

まずは、各動物を実装します。今回もDart言語を使用しています。

<動物>

// 犬
class Dog {
  String name = "犬";
  String cry = "わん";
  int speed = 5;
  // 鳴く
  String toCry() {
    return cry;
  }
  // 走る
  double run(int distance) {
    return distance / speed; 
  }
}
// 猫
class Cat {
  String name = "犬";
  String cry = "わん";
  int speed = 5;
  // 鳴く
  String toCry() {
    return cry;
  }
  // 走る
  double run(int distance) {
    return distance / speed; 
  }
}
// 象
class Elephant {
  String name = "犬";
  String cry = "わん";
  int speed = 5;
  // 鳴く
  String toCry() {
    return cry;
  }
  // 走る
  double run(int distance) {
    return distance / speed; 
  }
}

データとメソッドが1つにまとまっています。これらを使用しプログラムを実装します。

<ソースコード>

// 犬
class Dog {
  String name = "犬";
  String cry = "わん";
  int speed = 5;
  // 鳴く
  String toCry() {
    return cry;
  }
  // 走る
  double run(int distance) {
    return distance / speed; 
  }
}
// 猫
class Cat {
  String name = "猫";
  String cry = "にゃん";
  int speed = 4;
  // 鳴く
  String toCry() {
    return cry;
  }
  // 走る
  double run(int distance) {
    return distance / speed; 
  }
}
// 象
class Elephant {
  String name = "象";
  String cry = "ぱおん";
  int speed = 20;
  // 鳴く
  String toCry() {
    return cry;
  }
  // 走る
  double run(int distance) {
    return distance / speed; 
  }
}

void main() {
  Dog dog = Dog();
  Cat cat = Cat();
  Elephant elephant = Elephant();
  
  // ----------------------------------------------
  // 動物に鳴き声を出力する
  // ----------------------------------------------
  animalCry(dog.name, dog.toCry());
  animalCry(cat.name, cat.toCry());
  animalCry(elephant.name, elephant.toCry());
  
  // ----------------------------------------------
  // 動物に1000メートル走してもらい一番を決める
  // ----------------------------------------------
  const int runDistance = 1000;
  double dogTime = dog.run(runDistance);
  double catTime = cat.run(runDistance);
  double elephantTime = elephant.run(runDistance);
  // 最も速い動物の判定
  String fastestAnimalName = "";
  double fastestTime = double.maxFinite;
  if (dogTime < fastestTime) {
    fastestTime = dogTime;
    fastestAnimalName = dog.name;
  }
  if (catTime < fastestTime) {
    fastestTime = catTime;
    fastestAnimalName = cat.name;
  }
  if (elephantTime < fastestTime) {
    fastestTime = elephantTime;
    fastestAnimalName = elephant.name;
  }
  print("1000メートル走で最も早いのは$fastestAnimalNameです。");
}

// 鳴き声を出力する関数
void animalCry(String name, String cry) {
  print("$nameの鳴き声は「$cry」です。");
}

// 距離ごとのタイムを計算する関数
double calcRunTime(int runDistance, int speed) {
  return runDistance / speed;
}

<実行結果>

犬の鳴き声は「わん」です。
猫の鳴き声は「にゃん」です。
象の鳴き声は「ぱおん」です。
1000メートル走で最も早いのは象です。

できました。うん、各動物をオブジェクト化しただけでは、今いち効果が分からないですね。
前回のサンプルから幾つか劣化している気もします。
オブジェクト指向言語に用意されている要素をほとんど使っていないこと、オブジェクト化が中途半端なことが原因です。一部まだ関数使っていますし。

今回はオブジェクトの概要を振り返れたので良しとします。

次回以降、カプセル化・継承・ポリモーフィズムを使って改善していきます。




この記事が気に入ったらサポートをしてみませんか?