はじめに
プログラム初学者の方がJavaやPythonのようなオブジェクト指向言語を初めて学ぶと、多くの方がクラスとオブジェクトの考え方に躓く様です。よくプログラミングの入門書には「クラスは概念を表す型で、オブジェクトはその実体で…」なんて説明と、たい焼きを焼く例え話などが載っていたりもしますが、それを読んだところでなかなかピンとこないものです。「Javaのnewって何なの?」「どうして必要なの?」初学者の誰もが思う疑問なのではないでしょうか?
そこで、クラスとオブジェクトのイメージを作るのに、助けになる様な考え方を少し説明してみたいと思います。
そうは言うけれど...
オブジェクト指向は世の中にある「概念」の性質(「属性」「振る舞い」)とそれら概念同士の関連を定義し、プログラム設計に落とし込んだものと言われます。なので自然なプログラム構造になるのだと。
むー、そう言われてもなんかピンと来ませんね...ちょっと具体的な例を挙げて考えてみることにしましょう。
例題:市役所に住民票を取りに行く
今の時代としてはアナログですが、「市役所に住民票を取りに行く」を例に考えてみましょう。こんなシナリオです。
住民票を取りに行く
- 市民が市役所に来るとシナリオを開始します
- 市民が住民票の申請書を書き、担当窓口に持って行きます
- 担当窓口の人は、申請書の記載をチェックし、問題がなければ、発行担当に申請書を渡し住民票の発行を依頼します
- 発行担当はPCとプリンタを使って住民票を印刷し窓口担当に渡します
- 窓口担当は住民票の記載をチェックし、問題がなければ窓口に来た市民へ住民票を渡して、シナリオ終了です
現実とはちょっと違うかもしれませんが、そこはまぁそれで。さて、ここにはどの様な概念が出てきたでしょうか。
・市民
・申請書
・担当窓口
・発行担当
などでしょうか。市役所やPC、プリンタなどもありましたが、話をシンプルにするため一旦割愛します。
「住民票を取りに行く」の一般的なイメージを人に説明したりするときは、こんな概念で説明することになりますよね。
人に例えて考えてみる
では、今度は具体的に「住民票を取りに行く」をイメージしてみましょう。近所の市役所に行って、みたいな。そこには具体的な人がいますよね。お兄さんが市役所に来て、申請書を一枚取り記載して、窓口の美人なお姉さんに渡すと、お姉さんは発行担当のおじさんに依頼して…って感じをイメージしましたかね?まあ、窓口が美人のお姉さんかは皆さんの想像にお任せしますが、実際に「人」がいることをイメージしますよね?
先ほどの概念に当てはめるとこんな感じです。容姿だけだと分かりにくいので、名前をつけてみます。
・市民 → お兄さん(田中さん)
・申請書 → 紙
・担当窓口 → 美人のお姉さん(鈴木さん)
・発行担当 → おじさん(山田さん)
「概念」って言葉は少し抽象的でつかみにくいので、「役割」と呼び変えておきましょう。さあ、少しは具体的な市役所の様子がイメージできたでしょうか。
引越しの季節で住民票を取りに来る人が多くなれば、「担当窓口」も二人になりますよね。鈴木さんと吉田さんとしましょう。この二人は「担当窓口」として同じ仕事をします。何をするかは人ではなく、「担当窓口」という「役割」に定義されているからです。そしていくら「役割」が決められていても、実際にそれをやる人がいないと何も動きません。
どうでしょう?もう何となく見えてきたでしょうか?
そう、ここで言う「役割」がクラス、鈴木さんや吉田さんのような「人」がオブジェクトです。なぜ"new"の様なオブジェクト生成が必要なのか、この例から想像できるかな、と思います。
ちなみに「申請書」もクラスと言えるでしょう。実際に記載された一枚の紙はオブジェクトです。
もう少しプログラムっぽく考えてみると
では、前述の例をもう少しプログラムっぽく考えてみましょう。
"依頼される"とか"渡される"と言うのは、される側にそういった振る舞いがあると考えられます。つまり"メソッド"を持っているわけです。「申請書」のように依頼された時に渡されるものがあるのなら、それはメソッドの"引数"になるし、依頼された結果、依頼者に対して返しているものがあれば、それは「返り値」となります。(当然、依頼する側にも何らかのメソッドがあり、その中で依頼している)
このように我々の世界での人への"依頼"は、プログラムの世界ではオブジェクトへの"メソッドの呼び出し"に該当するわけです。「オブジェクト指向は世の中にある「概念」の性質(「属性」「振る舞い」)とそれら概念同士の関連を定義し...」と言うのは、こういった考え方からも来るのだと思います。
少し余計な話をすると...
オブジェクトとは関係ない話ですがせっかくなので。普段、我々が住民票を取りに来たときは、担当窓口の人がどうやって住民票を作っているかは知らないし、気にしません。ましてや「発行担当」の存在も知りません。(覗いてればわかるかも知れませんが...)
とにかく申請書を決められた通り記載して、担当窓口に渡せば住民票がもらえる、と言うことだけわかっています。担当窓口がどうやっているのかは、どうでも良いのです。この"どうでも良い"状態が、「隠蔽(カプセル化)」です。こうなる様に設計しなくてはいけません。決してアクセス修飾子を"private"にすることだけが「隠蔽」ではないのです。
何でも「人」に例えてみよう
実際のシステムはとても複雑です。様々な役割が登場してくると思います。でも「人」に例えて考えることができれば、意外とすっきりと整理できるものです。例えば、データベースから会員情報を取得して表示する機能を考えた時には、「データベースから情報を取得する役割」のクラスと「会員」を表すクラスと「会員情報を表示する役割」のクラスがあると考えられます。それとそれぞれの役割に対して順番に、必要な情報を渡して依頼する「旗振り役のクラス」(コントローラーと呼ばれたりします)も必要ですね。
3人の会員情報を取得したなら会員オブジェクトは3つあるはずです。それぞれの役割のオブジェクトは通常は1つあれば事足ります。(様々な事情から複数のオブジェクトが生成されることはよくありますが)
どのタイミングでオブジェクトを生成するかは仕様やソフトウェア・アーキテクチャ、フレームワークなどによって変わります。初学者の間は、必要な時に生成すると思っておけば良いと思います。この辺りの考え方は実践を通して学んでいくことになるでしょう。
脱「初心者」を目指して
クラスとオブジェクトの理解は「想像力」がポイントです。アプリやロジックを「人」に例えることで、明確なイメージが作れる様になると思います。
クラスとオブジェクトの考え方が理解できれば、オブジェクト指向言語の理解は一気に進みます。ぜひとも、想像の翼を羽ばたかせて脱「初心者」を目指しましょう!