プログラミングをする上で、様々な書き方・概念がある中、必ず直面するのが「オブジェクト指向」というものです。
Java・Ruby・Python・C#等々言語に関係無くオブジェクト指向の概念は存在し、しかも急にカプセル化とかクラスとか言われてもイマイチピンと来ないですよね。
本記事では、オブジェクト指向とは一体何なのか?というところを例を用いて初心者でもわかりやすく徹底的に解説しました。
ぜひ、プログラミングを書く上での参考にして貰えると嬉しいです。
【そもそもオブジェクト指向って?】
定義としては、ソフトウェア工学構想の一つであり、ソフトウェア設計及びプログラムを記述する際に使用される考え方や概念のことを表すとされています。
つまるところ、プログラミングをする上で絶対にこの書き方で遂行しなければならないというルールではなく、このような考え方でプログラミングをしていく方法もありますよというものです。
実際に色々なプログラマーの方を見ていると、
- 「自分は絶対にオブジェクト指向でなければ嫌だ」
- 「いやいや手続き型プログラミングだろう」
- 「関数型プログラミング一択だよ」
等々、派閥みたいな事象にまで発展しております。笑
株式投資で言うところのテクニカル派(チャート重視)とファンダメンタル派(企業業績重視)みたいな感じですね。(わかりにくい例であれば申し訳ありません。)
ただ、「概念」である以上オブジェクト指向の説明は人によって変わってきたりします。
例えば「果物」という概念に対して、「甘い食べ物」と答える人もいれば、「樹木になるもののみを指す」と答える人もいたりと、各々が持っている「概念」に対しての考え方は千差万別です。
【オブジェクト指向が難しいと感じる理由】
上記でも説明しました通り、オブジェクト指向は「概念」となります。
ゆえに、これから「概念」の説明をしようとしていると考えたら何やら難しい感じがしませんか?
概念を理解しようとするのは難しいもので、理解したと思い込んでもやはりどこかでずれが生じたりするものです。
そもそも非常に曖昧な存在を完璧に理解する姿勢自体が正しいとは言い切れない部分もありますので、今回はオブジェクト指向という概念の大枠を掴み、理解する、ことを目標として話を進めたいと思います。
【オブジェクト指向のイメージ】
オブジェクト指向はモノを「作成」していき、それを「操作(役割)」するというイメージを持ちます。
わかりやすい例だと車です。
私たちは何気なく車に乗り、運転方法を教習所で学び、それ以降はあらゆる道路を車で走りますよね。
ですが、物凄い距離を走っているドライバーでさえ、車がどのような仕組みでエンジンが掛かり、そのエンジンがどのような仕組みで車を動かしているのかはほとんど知りません。
シリンダーの中でピストンが往復し、その往復運動をクランクシャフトで回転運動に変えて動力となるので車が動作する。
ということは知っていてももちろん良いには良いのですが、車を運転する上で知る必要は基本ありません。
「車の仕組みを作成」することと、「車を操作する方法」を切り分けているためこのようなことが起こるわけで、オブジェクト指向はまさにこの考え方であります。
【オブジェクト指向のメリット】
短いシンプルなコンテンツを作成してそれっきりというコンテンツの場合は、手続き型プログラミングで十分となりますが、複雑なコーディングだったり同様の記述が多数存在する場合だと厳しくなると思います。
先ほどオブジェクト指向は「モノ」と「モノの操作(役割)」に分けられると話しました、プログラム上で「モノ」が1個しか無い場合は特に意識する必要も無いのですが、例えば100個あったりしたらどうでしょうか?
プログラマーの方であれば重々承知だとは思いますが、実際にプログラミングをしていくと「モノ」の数は膨大になっていきます。
わかりやすい例
「モノ」の数が膨大になりがちなゲームコンテンツなどを作成するときには威力を発揮すると思います。
例えばRPGゲームを作成する場合、剣を持つキャラクターが100人いるとしましょう。(「剣を持つ」という部分のコードは全て同じとする。)の中から選べるとしたときに、100人全てを手続き型プログラムで書こうとすると膨大なコード数とあまりにも被る無駄なコードが生まれてしまいます。
そこで、「剣を持つ」という部分を定義として作成してしまえば、100人のキャラクターの「剣を持つ」というコード部分は全てその定義を引っ張ってくるだけど済むことになります。
仕様変更や複数人開発にも適している
もし「剣を持つ」部分に変更が起きた際も、100人分を変える必要は無く、「剣を持つ」定義部分を変更してしまえば済むので、仕様変更の点から見ても作業効率が上がります。
変更に対して柔軟に対応できるという点は魅力的ですし、そもそも仕様変更が起きやすい部分をあらかじめ抽出するという選択を取るのも賢いコーディングです。
また、複数人数で対応している時、例えば100人分のキャラクターを分担して開発しているとします。
オブジェクト指向で書いた場合、「剣を持つ」という定義は、作成者だけが知っていれば問題ありません。
他の開発者は、「剣を持つ」という根元を軸に、「銀髪」「女性」「黒い服を着ている」等の枝葉の部分だけを開発すれば良いことになります。
わざわざ「剣を持つ」という部分の中身に関して理解しなくても作業を進めることができますので、全体の作業効率も間違いなく上がります。
リスク観点のメリット
上記のように作業を分担し、100人分は同一のモノを使っているということはリスク観点から見てもメリットがあります。
手続き型で「剣を持つ」コードを100人分書き、それぞれに別の人が対応して開発している場合、「剣を持つ」部分を書き換えてしまう恐れがあります。
そうなってしまいますと、AのキャラとBのキャラで剣を持つ定義に差分が生まれてしまい、Bのキャラだけが動作不具合を起こすという事態を引き起こしてしまいかねないのです。
リスクを管理し、見える化しやすいという点でもオブジェクト指向で書くメリットと言えます。
【オブジェクト指向の用語】
オブジェクト指向とは?というところと、オブジェクト指向で書くメリットとは?というところ説明しましたが、いよいよもう少し深いところに入りたいと思います。
「モノ」とか「操作(役割)」と上記では書いてきましたが、オブジェクト指向ではそれぞれに対してちゃんとした用語が用意されております。
以下では、その用語に関して説明していきたいと思います。
オブジェクト(Object)
散々オブジェクトオブジェクトと書いてきたので今更感はありますが、「モノ」の部分に当たる用語がオブジェクトとなります。
先ほどの例で言いますと、「車」がオブジェクトになります。
世の中を見渡すとオブジェクトとなる対象は無数に存在し、例えば「人間」、「テレビ」、「パソコン」、「スマホ」、「飛行機」どれもオブジェクトとなります。
「車」というオブジェクトを見たときに、でも車には色んな部品やらが付属していますよね?
タイヤや、窓、ワイパーにエンジン、それらを全て設計図通りに兼ね備えたのが「車(オブジェクト)」であり、その車が走ったり停車したりドリフトしたりするわけです。
クラス(Class)
オブジェクトの説明で、設計図通りに組み立てたのが「車(オブジェクト)」と書きましたが、クラスはその「設計図」の位置に当たります。
計4個のタイヤをこの位置に付ける…窓はこのサイズで…ボディの色は白色で…等々皆さんが想像するような設計図です。
プロパティ(Property)
車(オブジェクト)には、窓やタイヤ、ワイパーにエンジン…が付属していると書きました、プロパティはこの付属部品の部分を指し示します。
直訳では「属性」と表現されます。
メソッド(Method)
車(オブジェクト)の動作(処理)のことを指し示します。
「走る」「止まる」「ドリフトする」等々がメソッドに当たります。
以上のように、細かく説明しましたが全体を通して一連付けますと、
という流れになります。
実際にコードを書くとどうなる?
オブジェクト指向で使われる基本用語に関しては説明しましたが、では「実際にコードを書こうとしたらどうなるのか」という点を解説したいと思います。
「オブジェクト・クラス・プロパティ・メソッド」の関係式はざっくりと下記の形になります。
よりわかりやすく、具体的に車で置き換えて記述するとこうなります。
class Car {
String window; //窓
String tire; //タイヤ
Int speed; //速度
void start() {
System.out.println(“発車”);
}
}
インスタンス(Instance)
インスタンスもオブジェクト指向で書く上では必須の項目となります。
インスタンスは直訳で「実体」を表します。
急に「実体」と言われても何のことやらとなるかとは思いますが、オブジェクトが何かを作成することをインスタンス化と言います。
クラス名 参照変数 = new クラス名();
という形で作成します。
【オブジェクト指向三大要素】
更に、オブジェクト指向を語る上で重要となる三大要素が存在します。
それが、「カプセル化」「継承」「ポリモーフィズム」と呼ばれるものなのですが、初めて聞く人にとってはさっぱりかと思います。
カプセル化→あー何かカプセルっぽくまとめるのかな?
継承→あー何か引き継ぐのかな?
ポリモーフィズム→?????日本語でお願いします。
急に言われてもこうなるのが当然かと思います。
そこで、オブジェクト指向で重要なこれら三大要素をひとつずつ解説します。
カプセル化
簡単そうに見えて非常に重要かつ難しいのがカプセル化です。
カプセル化は抽象化であり、無駄を省くために洗練化させて分かりやすくすることです。
記述の中で、互いに関連するデータの集合とそれらに対する操作をオブジェクトとして一つの単位としてまとめ、外部に対しては必要な情報や手続きのみを提供しつつ、外部から直接参照や操作をする必要の無い内部に関しては隠すことを表します。
細かく紐解くと、オブジェクトが持つプロパティやメソッドの中で、他のオブジェクトから直に参照や操作をする必要の無いものは隠されるということであり、万が一使用する場合は用意された手続きを踏んで利用するということです。
先ほどの例で照らし合わせますと、オブジェクト(車)が持つプロパティ(窓やエンジン)やメソッド(走ること)の中で、他のオブジェクト(例えば飛行機)から直に参照や操作をする必要の無いもの(例えばエンジン)の内部の状態や構造は隠される。ということになります。
カプセル化をすることは、作業を効率化させる上で非常に重要です。
上記のエンジンに関して、中の仕組みまで理解しなくてもエンジンを動かす手続きさえ知っていれば、動作部分のコード開発者は作業できるわけです。
先ほど、「剣を持つ」という特徴を持つRPGキャラ100人も、全てにその特徴を記述するのではなく、「剣を持つ」という定義だけあれば、あとはそれを呼び出すだけで、その他の「銀髪」「女性」と言った枝葉の部分をコーディングするだけで良いという話をしましたが、まさにこの「剣を持つ」という部分が「カプセル化」なのです。
「銀髪」部分をコーディングする人にとっては、「剣を持つ」という中身のコーディングを知る必要は一切無く、むしろそれが見えてしまっていると理解しなければならないという作業に無駄が発生してしまうため、内部を秘匿化しておくことが大切なのです。
これが抽象化であり、無駄を省くために洗練化させて分かりやすくすること。なのです。
ただ、カプセル化をする上で重要なのは、「役割を一つにする」ことです。
「剣を持つ」という特徴の中で、「たまに斧を持つ」とか、「自動回復する」とかを入れてしまうと、分かりやすく洗練されたカプセル化とはほど遠い存在に成り下がってしまいます。
カプセル化では、「守備範囲を広げる」ことではなく「明確で分かりやすい」ということが何よりも大切なのです。
継承
ロマンシングサガ2をやっている人にはお馴染みの継承(え)。
親の機能を受け継ぐというのは継承の本来の意味ではありますが、オブジェクト指向では特定のオブジェクトの機能を引き継いで使用することを表します。
類似したオブジェクトをたくさん作る時に、プロパティ・メソッドを毎回コーディングするのは時間的にもコード数的にも無駄なので、元となる親から引っ張ってきてラクしましょう。ということです。
例えば「乗り物」という親要素がいたとします。
「車」や「バイク」、「自転車」を説明しようとした時に、毎回「乗り物」コーディングを記載していたらコード数が増えてしまいます。
そこで、「乗り物」という親要素から継承することで、毎回その部分を書く必要は無くなります。
わーい!楽だ!継承使いまくろう!と思う部分はあるのですが、注意点があります。
それは継承を多用することで、関係性が逆転した記述を書いてしまう人がいることです。
乗り物と車の関係は、部分集合の関係になります。
上記の図で言うとBが乗り物でAが車です。
これが逆転することは有り得ません。
何故なら、車は乗り物ですが、乗り物だからと行って車とはならないからです。
乗り物はバイクもあれば飛行機もあります。
一見単純で、それは当たり前だろう!とも思うのですが、コーディングをしている上でこの関係を逆に書いたりして継承してしまっている人が少なからずいます。
「親から子へ」という関係を常に意識して継承をするようにしましょう。
ポリモーフィズム
日本語でよろしくのポリモーフィズムの登場です。
英語で書くと「Polymorphism」で、直訳は「多様性」です。
例えば「エンジンの仕組み」は、決して車を動かすだけのものではありません。
動力という観点で、あらゆるものに応用が効いたりします。
この考え方は、再利用という点で継承に近い部分はありますね。
ただ、継承ばかりでは同じ振る舞いをするプログラムしか作成できないですが、ポリモーフィズムでは、同じ振る舞いをする根幹部分は共通ですが、目的に合わせて違う振る舞いに変えるという枝葉の部分での調節が可能です。
このように、ポリモーフィズムではより柔軟に振る舞いを引っ張ってくることが可能です。
ポリモーフィズムに関しては、言葉では理解しにくい部分がありますので、実際にコーディングしていく上でピンと来る部分もあるかと思います。
ここでばっちりと理解していなくても不安になる必要はありません。
以上で、オブジェクト指向とは?メリットとは?用語とは?をざっくり説明しました。
本記事では、オブジェクト志向という概念の大枠を捉える部分に焦点を当てましたが、具体的なコーディングの話も無いと分かりにくい部分もあるかと思いますので、別記事にてコーディング部分を説明したいと思います。
JavaScriptで書くオブジェクト指向とは?サンプルを用いて徹底解説!
以前オブジェクト指向とは?に関して大枠を掴むための記事を書きました。 今回は、オブジェクト指向で実際に書いてみて内容をより深く知るための記事です。 JavaScriptを対象として記載するので、Jav ...
続きを見る