オブジェクト指向とは、プログラミングをする上でなくてはならない概念だ。
プログラミングをする上で避けて通れないが、理解するのが難しい。
- モノとして考えるんだ
- 現実世界と一緒だ
- 車を例に挙げてみよう
と言われてもわからないものはわからない。
オブジェクト指向とはいったいどんな考え方なのか? このページでは、オブジェクト指向のイメージを掴んでもらえるように、できるだけ簡単に説明した。オブジェクト指向について知りたい方は参考にしてほしい。
オブジェクト指向とは?の前に
オブジェクト指向に明確な説明はない
まず、はじめに理解しておきたいことがある。オブジェクト指向は「概念」だ、ということだ。概念という言葉自体も難しいが、なんとなく意味はわかるだろう。物事や対象を丸ごとひっくる見たときの大まかな理解のことだ。
なんとなく意味はわかっても、人それぞれ解答が違うだろう。時代や国によっても答えは違うはずだ。
オブジェクト指向もこのように曖昧なものだと思ってほしい。愛や国家ほど漠然としたものではないが、人によって「どこが本質か?」「何が正しい説明か?」が違う。
だから、オブジェクト指向は難しく感じる
オブジェクト指向について説明している技術書やWebサイトは数多く存在するが、どの説明もバラバラだ。言葉も無駄に難しい。語っている本人たちは理解して語っているが、それを読む初心者にはたまったものではない。
あるサイトでオブジェクト指向について調べてなんとなく理解できたようでも、別のサイトを見て説明が違っている場合、理解したと思っていたことが本当に正しいかどうかわからなくなる。
実際、10年やっていても20年やっていてもどこが本質か?の答えはエンジニアによってバラける。
100%理解しようとするからよくわからなくなる。
「ベテランエンジニアは色々とごちゃごちゃ言っているけど、なんとなくこんなもんかな?」くらいの理解で構わない。その状態になれただけで十分な成長だ。
あとは自分の成長と共に、理解が進んでいくし、自分の中で定義ができるようになるだろう。
オブジェクト指向とは?
それでは、オブジェクト指向の説明に移っていこう。
オブジェクト指向は対象を操作するイメージ
オブジェクト指向プログラミング(Object Oriented Programming: OOP)とは、プログラムを手順ではなくて、モノの作成と操作として見る考え方だ。オブジェクトとは「モノ」を意味する。
「テレビ」というモノを操作するとき、中でどういうプログラムが動いているか知る必要はない。リモコンで操作すれば、動く。
「こういう”モノ”を作りましょう」「そして、その”モノ”を使いましょう」というのがオブジェクト指向という考え方だと思っていい。なぜモノを作っておくと便利なのか?
大変な作業を無くす
プログラムというのは上から順番に動作手順を書いていけばとりあえずは動く。しかし、場合によっては大変だ。
次のレーシングゲームを想像しよう。
- ○○車はAボタンを押すと走る。Bボタンを押すと止まる
- △△車はAボタンを押すと走る。Bボタンを押すと止まる
- □□車はAボタンを押すと走る。Bボタンを押すと止まる
とそれぞれプログラミングしてもいいが、1万種類車種があったらどうだろうか? このプログラミング担当者は苦痛だろう。
なんとかプログラミングをこなしても、途中でマネージャーが「やっぱりCボタンを押したらバックする機能を追加しよう!」と言い出したらどうだろうか?
もちろん1万個のプログラムを全部書き換えることになってしまう。絶望を感じるだろう。
そうならないために、「車」というモノをはじめから定義しておいて、それを使ったほうが楽だ。
- 「車」というモノを先に作っておいて、Aボタンを押すと走る。Bボタンを押すと止まるようにしておく
- ○○車は「車」をコピーして外装の色だけ赤にする
- △△車は「車」をコピーして外装の色だけ青にする
- □□車は「車」をコピーして外装の色だけ緑にする
こうしておけば、「Cボタンでバック」という機能を追加するとき「車」プログラムだけを変更すればいい。
大人数で開発するときに便利
「車」というモノを用意しておけば、大人数で開発するときにも便利だ。「車」というプログラムは作成者だけが中身を知っていればよく、他の人は「Aボタンを押すと走る。Bボタンを押すと止まる」だけ知っておけばいいことになる。
手順を全部書いたプログラムだと、他のプログラマーも中身を理解していないといけない。下手したらプログラムを壊してしまうかもしれないからだ。
モノを用意して、それを他の人が触れないようにしておけば、他の人がプログラムを壊してしまう心配がなくなる。
同じようなモノを作りやすい
レーシングカーにトラックを登場させるとしよう。「Aボタンを押すと走る。Bボタンを押すと止まる」という機能は車と一緒だ。
この機能は再利用すべきだろう。これもオブジェクト指向の考え方だ。
すでにあるモノをうまく使って、加工したモノを作れば効率は良くなる。
オブジェクト指向の基本用語解説
オブジェクト指向の考え方と、なぜその考え方が大切かイメージできただろうか? ここから詳細に入っていく。わかるところまで付いてきて頂きたい。
オブジェクト指向には基本となる用語がある。これらはすべて理解して覚えておきたい。
オブジェクト(object)
オブジェクトは、オブジェクト指向の根本だ。
先ほども出てきたが、オブジェクトとは「対象」「物」という意味で、プログラミングにおいてはデータと処理の集まりを意味している。オブジェクト指向で現実のものを例えると、このブログを見ているあなたもオブジェクトであり、使っているPCやスマホもオブジェクトだと言える。
あなたには「名前」や「性別」といったデータ(個体の情報)があり、何かを「見る」「聞く」「話す」といった処理を持っている。
下で説明するクラスとの違いがわかりにくいが、設計図から作った実物がオブジェクトだ。下図を眺めてから次の説明を確認してほしい。
クラス(class)
クラスとはオブジェクトの設計書のようなもので、オブジェクトの中のプロパティやメソッドをひとまとめにしたものだ。
例えば実際に作られた車はオブジェクトだが、車の設計図はクラスだ。割と抽象的な概念なので、ここでは「クラスとは設計書である」と覚えておこう。
プロパティ(property)
オブジェクトが持っているデータのことをプロパティ(属性)と言う。車の例えだと、車というオブジェクトは「メーカー」、「排気量」、「色」といったプロパティを持っていると言える。データにはさまざまな種類があり、たとえば「速度」などといったオブジェクトの状態を示すものもある。
カプセル化
オブジェクトが持つデータや処理のうち、別のオブジェクトから直接利用される必要のないものを隠すことを言い、利用する場合は外部から操作するために作られた処理を設けることを言う。先ほどのレーシングカーの例でも出てきた、オブジェクト指向の基本概念だ。
プログラムが壊れにくくなるし、大人数で開発をするときすべてのコードを認識する必要がなくなる。
継承
特定のオブジェクトの機能を引き継いで使うことを継承と言う。レーシングカーの例だと”車”からトラックを作るという話があったが、あれが正しく継承だ。
似たようなオブジェクトを複数作る時に、全てのプロパティやメソッドをいちいちプログラミングするのは非常に手間が掛かるが、継承を使うことにより、同じ機能を実装できる。これについては後ほど紹介するサンプルプログラムを見ると分かりやすいだろう。
ポリモーフィズム
ポリモーフィズムもオブジェクト指向プログラミングの基本性質だ。
世の中の家電は、説明書を見なくてもだいたい使い方がわかるだろう。また、車はどの車種であってもアクセルが右というふうに決まっている。
同様にプログラムも同じ処理の名前で動いてくれると、処理名を覚える必要もないし、ミスも減らせてハッピーだ。
クラスによって同一のメソッドで異なる処理が行えるという性質をポリモーフィズムという。
よくわからない部分もあると思うが、これに関しては学習を進めてから理解すればいい。名前だけ覚えておこう。
勇者に学ぶオブジェクト指向プログラミング
ある程度基本となるオブジェクト指向の用語を説明したが、理解できただろうか?
さらに理解が進められるように、ここでJavaのサンプルプログラムを紹介する。プログラミング初心者でJavaがよく分からないという方は飛ばしていただいて構わない。
サンプルプログラムはRPG(ロールプレイイングゲーム)風のシチュエーションにしている。勇者、魔法使い、僧侶の3人のパーティが、ラスボスと戦うシーンを思い描いてほしい。
人間クラス(Human.java)
RPGに登場する人間の基本的なプロパティ、メソッドを設定する。
勇者クラス(Yuusya.java)
人間クラスを継承したクラスで、勇者特有の必殺技メソッドを持つ。
サンプルプログラムの解説
それでは解説していこう。まず各キャラクターのベースとなるHumanクラスから。
Humanクラス
Humanクラスには身長、体重、体力などRPGのキャラクターのベースとなるプロパティや、話す(talk)、食べる(eatFood)などのメソッドが設定されている。各プロパティは公開範囲がprivateなので、データを参照したり変更したりするには「setName」、「getName」といったsetter、getterと呼ばれるメソッドを使う必要がある。消化する(digestFood)というメソッドもあるが、これは体の内部のことで公開する必要もないため、カプセル化の際に隠しているのがわかる。
Yuusya、Wizard、Crelic、LastBossクラス
それぞれのクラス名の右側に「extends Human」と書かれているが、これはHumanクラスを継承することを意味している。Humanクラスを継承することにより、話す、食べるといったHumanクラスが持つ人間の基本動作をそのまま利用することができるのだ。
さらに、継承した機能に加えて、それぞれのキャラクターは必殺技や魔法攻撃のメソッドを持っている。継承した上で追加のメソッドやプロパティを設定することで、別の機能を実装できるのだ。
また、最初に呼び出される際、「コンストラクタ」と呼ばれる処理によって、各キャラクターの身長、体重、体力などが設定される。コンストラクタとはオブジェクトを最初に作る時に実行される処理で、オブジェクトの初期化処理などを書くケースが多い。
メイン処理
ここではプログラムの流れが書かれている。最初に各キャラクターのオブジェクトを生成しており、ここで初めてオブジェクトに命が吹き込まれてRPG風の戦闘が始まる。各キャラクターの攻撃メソッドにターゲットを指定して呼び出せば、ターゲットの体力が減少する。僧侶の場合はターゲットを指定して回復メソッドを呼び出せば、ターゲットの体力が回復する処理となる。
メソッドのターゲットの指定には、Humanクラスを設定している。Humanクラスは全キャラクターが継承しているクラスなので、どのキャラクターでも対象として指定できるのだ。
回復アイテムを使用すれば、アイテムによって回復するプロパティや分量が変わるように設計されている。Humanクラスの食べるメソッド(eatFood)を呼び出すことで、Humanクラスで設定された消化メソッド(digestFood)が呼び出され、回復する仕組みだ。消化メソッドはカプセル化によって隠されているので、呼び出し側は消化まで意識する必要はない。
そして最後に各キャラクターのステータスを表示している。最初に生成したオブジェクトごとにプロパティの値は異なっており、また戦いによるダメージによって各キャラクターのプロパティが変わっているのがわかるだろう。
実際にプログラミングしながら理解を深める
オブジェクト指向の基本について、できるだけ分かりやすく紹介したがいかがだったろうか?
オブジェクト指向とはいったいどのようなものか、イメージだけでも掴んでもらえたら幸いだ。もちろん、ここで紹介した内容がオブジェクト指向の全てではなく、理解するには更に知識を深める必要がある。
おすすめなのは、技術書などを読んでみるだけではなく、実際にプログラミングしながら理解することだ。そうすることにより、プログラミングスキルを身に着けながら、オブジェクト指向に関する理解も深まりやすい。
まずは上記プログラムを組んでみることをオススメする。JavaがわからなければPHPでも何でも構わない。Webで検索するとたくさんの実例が出てくる。トライしてみよう。