コラム

最速でプログラマーを育てるアクセライトメソッド ~Lesson4 オブジェクト指向編~

カテゴリ:システム開発
Author:大下知樹

こんにちは、システム開発部の大下です。
第4回のレッスンはオブジェクト指向を学ぶ、です。

オブジェクト指向とは、とある一つのパラダイムです。2000年あたりでは、プログラミング言語を学ぶのに際し、まずは基本となるC言語を学び順を追ってC++を学ぶべきか、あるいは最初からC++を勉強して効率的にオブジェクト指向を習得した方が良いか、などと議論が生じるくらい、オブジェクト指向を学ぶということがかっこよくて主眼におかれる時代でした。

最近はオブジェクト指向という言葉自体をあまり話題にしなくなっているようで、大体言語の入りといえばpythonが流行りですね。ポインタを学ばなくてよくなったなんて、なんと素晴らしい時代でしょう。プログラムが思い通りに動かなくてPCの前で一人涙する悲しみから人類は解放されました。

オブジェクト指向そのものを知らないで立派なプログラマになることは流石に難しいのですが、開発を始めたいという初期段階において、オブジェクト指向を学ぶことは必要なのでしょうか。

正直なところ、必要な気もしますし、不要な気もします。

世の中すっきり割り切れることばかりではありません。もしかしたら必要になるかもしれないので、一旦判断は保留にして、ここではあくまで簡単に学んでおきましょう。

オブジェクト指向とは

一応、オブジェクト指向というと、以下のような特徴があるようです。

  • 変数とメソッドの集合
  • クラス間の継承
  • メソッドのオーバーライド
  • オブジェクトのカプセル化
  • メソッドのポリモーフィズム

なんだか難しそうですね。実際、真面目に取り組むと結構難しいですし、真面目に取り組んだ結果挫折したという人も結構多いものと思われます。個人の話で恐縮ですが、私自身はC++のダイヤモンド継承を学んだときに挫折しました。結果的によりシンプルなJavaに逃げて私のキャリアは絶たれずに済みました。『独習C〇〇』にはダイヤモンド継承のセクションにおいて、「まあこんなものは使わないけどね」と是非とも併記していただきたいです。

オブジェクト指向は、なぜ語られなくなったのか

さて、なぜオブジェクト指向を語ること・語られること自体が減ったのでしょうか。それはそもそもオブジェクト指向は人間には早すぎたとか、好き勝手にオブジェクトを継承するような設計はするべきではないとか、そういった悲しい理由が背景にあるようです。どちらかというとオブジェクト指向を強く意識しなくてもコードがかけるような体制・設計にすることが良いプラクティスになったのでしょう。

ですが、それなりの開発力を磨くためには、割と序盤でもオブジェクト指向をしっかり理解しておくことは必要になります。

そのようなわけで、オブジェクト指向を難しく語ることはやめましょう。それほど難しい設計はしないからです。
とりあえず課題としてはこのような感じです。


上記の課題においては重要な概念がたくさん抜けていますが、問題ありません。

本レッスンは体系的に学ぶことではなく、プログラマとしてとりあえずの即戦力になることを目的としています。

継承が云々、カプセル化が云々、デザインパターンが云々、というのは初期段階では不要でしょうし、疑問に思ったところや興味をもったところから後付けで学んでいきましょう。それが嫌でもっと体系的に学びたいのであれば技術書を読み進めるか情報系の学科で学ぶかプログラミングスクールに通いましょう。その場合はそれなりの覚悟が必要ですし、残念ながらこのコラムはそのような目的には適っていません。

オブジェクト指向とは、改め

とはいえ、これまでの説明ではさすがに雑でした。もう少し基本的なことを理解しやすい流れで説明します。

「変数と関数を含んだ存在を作ることができる。そしてそれをオブジェクトと呼ぶよ。」

これが全ての始まりです。そしてオブジェクトの関数は特にメソッドと呼ばれます。

プログラミングはまずは変数から始まるわけです。

以下のように変数には単一の値であるスカラー値を変数に格納することができます。

$a = 1; // int 整数
$b = 3.2; // float 浮動小数点数
$str = “test”; // string 文字列

※stringは厳密にはスカラー値ではなく、文字というスカラー値の列ですが、わざわざ恐ろしいエリアに踏み入るのは止めましょう。

そしてそれだけでは不便で、スカラー値を並べてベクトル値のように扱いたいという欲望がでてきまして、それをかなえるために配列あるいは連想配列が登場します。

$list = array(1, 3, 5, 10, 99);
print $list[2]; // 5が表示される

配列はたいていの言語では 0番目から始まります。これはいろいろと便利です。

仮にビルが0階から始まっていれば、地下1階(-1階)から地上2階まであがるのに 2 – (-1) = 3階分 として処理ができたはずなのですが、実際は何故か地下1階から2階あがるだけ地上2階に到着するのです。

西暦が0年から始まったり、世紀が0世紀から始まっていたら恐らく人類は西暦⇔世紀の換算から解放されていたはずなのですが、これはもう仕方のないことですね。(ところで今は何世紀でしたっけ?)

実社会への不満はさておき、ひとまず私たちプログラマは様々なスカラー値と、スカラー値の列(ベクトル値)を扱えるようになりました。

多くの学生がいて、身長、体重を管理するプログラムを書きたいとします。

$height_list = array(152, 149, 158, 153);
$weight_list = array(51, 45, 54, 55);

として、1人目の身長、体重をそれぞれ

$height_list[0], $weight_list[0];

などと収集するのも悪くはないですが、3人目のデータを削除して詰めるときに体重だけ処理をわすれて二つの配列の要素数がずれていたらどうしようとか、不安が生じますね。どうしましょうか。

$student_list = array(array(152, 51), array(149, 45), array(158, 54), array(153, 55));

のように、1人ずつのデータを配列として、さらにそれを配列にする(多次元配列)というのは悪くないですね。少なくとも各個人の身長・体重が1人分ずつずれるといった問題からは解放されます。余計な不具合を回避するよう設計しておくことはプログラミングにおいて大変重要な心掛けです。

これはこれで良いのですが、新たな問題が生じます。

2人目の身長にアクセスする際は

$student = $student_list[1];
$height = $student[0]; // 身長は最初に入っている前提

のようになります。身長は最初に入っている前提です。

現在では測定が廃止になりましたが、座高を新たに入れるとしたらそれは何番目に入れる修正になるのでしょうか。まあおそらく身長、体重の次で3番目ですね。では年齢を追加したかったとしたら?

身長、体重がそれぞれ1番目、2番目に入っているという前提が崩れると、あらゆる参照箇所で修正が発生します。これはしんどいし、ミスを誘発しますし、実際にこうしたことが原因で不具合が発生します。もう一度言いますが、実際にこうしたことが原因で不具合が発生します

そこで登場するのが連想配列です。

$student = array(“height” => 152, “weight” => 51);
print $student[“weight”]; // 51が表示される

このように何番目かという記述ではなく、あるキーとなる文字列に値を紐づけておくことで、キーの追加が容易になります。

$student[“sitting_height”] = 79; // 座高
$student[“age”] = 14; // 年齢

のように新しい項目を追加することができるようになります。参照側への影響もほぼなさそうですし、これは便利です。

ちなみに、連想配列は言語によってハッシュ(hash)やディクショナリ(dictioinary)やマップ(map)等と呼ばれたりしますが、同一のものです。Key-Value Store (KVS)と呼ぶともっとかっこいいですが、概念としては非常に単純なもので、まさに key と value の組み合わせのstoreです。NoSQLやmemcachedあたりで根幹となる考え方なので、結構大切です。

さて、ここでやっとオブジェクトが登場します。

オブジェクトは変数と関数を含んだものであると説明しました。

オブジェクトが変数だけを持つ場合、実は上記の連想配列と等価の存在となります。言語によっては記法が異なることが多く、PHPでは、

$student = new StdClass(); // オブジェクトの作成
$student->height = 152;
$student->weight = 51;
$student->age = 14;
print $student->height; // 152と表示される

のようにオブジェクトを作り、オブジェクトを配列にするという構造で生徒の一覧を管理することができます。

オブジェクトが便利なのは、さらにここにそのオブジェクト用の関数を作ることができるということです。

そのためには事前にStudentというクラスを定義しておき、

class Student {
  int height;
  int weight;
  int age;

  // コンストラクタ
  function __construct($height, $weight, $age) {
    $this->height = $height;
    $this->weight = $weight;
    $this->age = $age;
  }

  function getBMI() {
    $bmi = $this->weight / ($this->height / 100)^2;
    return $bmi;
  }
}

初期化や、BMI値の算出等が

$student = new Student(152, 51, 14);
print $student->getBMI(); // 22.074… と表示される

のように実現できます。

だんだん便利になってきましたね。このあたりまでは確実に理解しておくのが必須です。

オブジェクト指向とは、改め2

オブジェクト指向で次に知っておくべきとしては継承でしょう。

先生が生徒を管理するためのシステムを開発し、先生は生徒のあらゆるデータを管理していました。

ところが世知辛いもので、今や先生が生徒から評価される時代です。

ついには先生自体もそのシステムで管理されるようになりました。

先生用のclassを定義しましょう。

class Teacher {
  int height;
  int weight;
  int age;
  int score; //生徒からの評価!?

  function getWage() [
    // 賃金が自動で算出される!?
  }
}

これでいろいろと管理できます。

ですが、よく考えてみると生徒と先生は同じ人間です。身長、体重、年齢あたりは共通の変数ですね。プログラミングで重要なこととして、繰り返しを避ける、という鉄則があります。

ということで、まずは人間のためのclassを定義してみましょう。

class Human {
  int height;
  int weight;
  int age;

  // コンストラクタ
  function __construct($height, $weight, $age) {
    $this->height = $height;
    $this->weight = $weight;
    $this->age = $age;
  }
}

そうしますと、Teacher classは以下のように簡便に定義することができるようになります。

class Teacher extends Human { // Humanクラスを継承する
  int score;

  function getWage() {
     $ret = age * 10000;
     $ret +=  score;
  }
}

このような形でTeacher用の変数や関数を独自に定義し、同様にStudent用の変数や関数も独自に定義することで、それぞれの違いを表現できます。

大体このくらいで十分ですかね

ただし、最初にも述べましたが、オブジェクト指向はやや人類には早すぎました。特に継承はその最たるものでしょう。入門書にしばしば事例として記載されるのですが、Humanって、Animalだよね。そういえばAnimalって、Creatureだよね。そしてCre(以下略)

なんて、設計者が考え出すのは自由ですが、それを本当にclass定義されちゃったら日にはどうしましょう。まあこれはさすがに極端な例ですが、オブジェクト指向にはここでは紹介しきれない深さがあります。そして事実は小説よりも奇なりです。深い闇に触れるのはやめてここら辺にしましょう。

シンプルに考え取り組めばオブジェクト指向はとても便利で強力なものです。

楽しんで学びましょう。

次回はレッスン5、ウェブアプリケーションを組む、です。

この記事を書いた人

大下知樹

営業/設計をメインに、空いている時間でプログラミングも担当。目的の達成にこだわり、言語にはこだわらない。初学者に優しいPHPが好き。