Unityでインディゲーム道!

プログラム、Unity初心者がインディゲーム制作を目指して日々思うことなどを書き綴ります。

オブジェクト指向をもっとシンプルに考える!変数と関数も。

オブジェクト指向プログラミングにおける初心者への説明はまどろっこしい。もっとシンプルに考えることは出来ないか、という試みです。とりあえず、変数と関数から行ってみます。

 

変数は箱のようなもので、箱じゃない

 変数は箱ではありませんし、そもそも変数と呼ぶことさえ抽象化であり、既存の概念を流用した例え話です。そうした方が人間の認識に都合がいいらしいので。ただ、問題なのは『箱のようなモノ』と言われて人が思い浮かべるのは、名札を貼り付けた箱だと言うことです。繰り返しますが、変数は箱じゃありません。
 プログラミングにおける変数とはメモリの一部分です。そして、型とはタイプになります。<T>のTはTypeのTです。


 変数の宣言とは、あるタイプのデータをコンピュータ上で扱いたいのでメモリの一部を使わせてほしい、とコンピュータに伝えることです。その結果、コンピュータはメモリの一部分をそのタイプに必要な分だけ確保し、プログラマの付けた名前と結びつけます。つまり宣言とはメモリの場所取りです。


 コンピュータ側は、それを箱のようなものどころか変数とすら思っていなくて、メモリ上のとあるアドレスの1区画にデータが保存されている、という認識です。人間が勝手に箱に例えているだけです。
 つまり、変数とは箱のようなモノという人間側の認識とはかなりのズレがあります。このズレこそポインタの難しさに繋がるのだと考えられます。

 

関数はミニプログラム

 また、関数とは再利用するためもの、と言われます。モジュール化、部品化という概念が出てきます。しかし、この説明も初心者にとって分かりづらい。なぜなら、再利用のメリットはある程度コードを自分で書いて初めて実感できることだからです。関数はもっとシンプルに言い表せます。


関数とは…


ある1つの仕事をする複数行のコードをまとめ、

明確で本質的な名前を与え、切り離したもの


です。

 関数の利点とは、他のコードから切り離し、その内容に沿った名付けをすることで、コードを読みやすくなるし、その結果名前を使って呼び出せばいいから再利用しやすくなる、ということです。つまり、順序が逆ですね。

 

 プログラムとは入力されたものを計算し、出力するものですが、関数も入力された引数を計算し、返すという性質を持っています。なので、ミニ・プログラムぐらいの認識がちょうどよい気がします。 (プログラムの中の小さなプログラム)

 

オブジェクト指向は普通の考え方

 そもそもオブジェクトとは何か?客体です。客体とは主観を持った他人です。つまり、オブジェクト指向とは仕事を分担して、それをその人に任せよう、というごくごく単純なものなのです。クラスは仕事を分割するためのものとなります。

 

 プログラミングにおける、様々な機能やテクニックは主に二種類に分けられます。コードを読みやすくするか、コードの量を減らして扱いやすくする、か。
 クラスとは、コードを幾分か分割し、読みやすく扱いやすくするための器です。ただ、どう分割するかが難しい。物事の本質を掴む能力が求められます。なので、オブジェクト志向が難しいのではなく、クラス設計が難しい、という方が正しいです。

 

 その上、分割したということはコードがバラバラになってしまっているので、それらをどう連携させるか?という問題も出てきます。そういう意味ではオブジェクト志向は完璧な方法論ではなく、リスクもあるということになります。しかし、大規模なプログラムに対しては、分割倒置法が現実的な対応策だというだけです。

 

 継承もコードを減らすための技術です。これも要は省略の技術です。ただ省略は理解してない人にとっては分かりにくい、というデメリットがあります。カプセル化は、コード群を意味のある、必然的なまとまりにして、関数のように他のコードと切り離して、分かりやすく管理しやすくしようというもの。

 情報隠蔽はバラバラになったコード同士が安全に楽に連携できるようにするためのものです。ポリモーフィズムとは違った形を持たせる、ということですが、要は関連性のある各クラスに共有されるメソッドに違った挙動を与える、ということです。

 

 法的手続きをしたい時は行政書士や弁護士に依頼します。あなたは法律知識を知る必要も実際に書類を用意する必要もありません。あなたはただ依頼して報酬を払えばいい。弁護士という仕事は社会のなかで1つの職業としてカプセル化されています。
 また、あなたは銀行でお金を引き落とせるが、金庫の中に入ることは出来ない。窓口かATMからしか引き出せません。これは機密情報がユーザーであっても安全のため隠蔽されているからです。
こう考えればオブジェクト志向って別に普通で順当な考え方ですよね。

 


 客体は主体を持った他人だと言いました。クラスを使って分割するだけでなく、オブジェクトに主体性を持たせることが大事です。つまり、自分の仕事を理解していて、必要な処理を自分で責任もって行うことが出来るということです。クラスの定義がしっかりしていて、必然性のあるメソッドが準備されているか、ということです。

 

操作するのではなく、命じよ

 クラスとはコードを分割するためのものです。しかし、同時にそのクラスに任せられた仕事を達成するような主体的な振る舞いを持たせなければならない。つまり、他のクラスとの関わりの中で、仕事の線引き(どっちが何をやる?)が大切になります。

 

ゲームで例えます。
 プレイヤーのキャラが敵キャラを攻撃をしました。敵にダメージを与えました。トリガーから検出した敵のコライダーを使って、Enemy classの参照を得たインスタンスを作ります。ダメージは互いの攻撃力と防御力を計算して出します。

これをコード上でどう処理すべきか。

 

 悪い例は、プレイヤークラスが敵クラスのプロパティから防御力を取得し、自分の攻撃力と合わせて計算。そうして出したダメージ量をHPから引く、という処理をプレイヤークラス内部で全てやってしまうことです。これはプレイヤークラスが敵キャラクラスのインスタンスを直接的に操作してしまっていますし、敵キャラクラスは自分では何もしない受動的な状態になってしまっています。

 

 そうではなく、敵キャラにaddDamageというようなプレイヤーから利用できるpublicなメソッドを用意しておいて、プレイヤーはただこのメソッドを呼び出し、自分の攻撃力を渡せばいい。

enemy.addDamage(Player.AttackPower)

 そうして、敵キャラクラスは渡された攻撃力を元にダメージ量を計算して、HPという風にダメージ処理という仕事をきちんとこなしています。

 これこそが各々の主体性が保たれた状態で、分業のあるべき姿です。プレイヤーは自分の攻撃力を伝えて、ダメージ計算するように敵キャラにお願いしてるだけです。

 

最後に

 このように説明すれば、オブジェクト指向が如何に自然で普通な考え方か分かります。別に難しくないっすよ。実際使いこなせるかはともかく。崇める必要も嫌悪する理由もまったくない。

 なんで、教本に書かれているような説明だとわかりにくいのでしょうか?もっとシンプルに考えるべきだと思います。

長々書きましたが、言いたいことはプログラマの皆さん、教えるの下手!

(そうじゃない方々は、救って頂きありがとうございました。)