こんにちは。shamojiです。
オブジェクト指向入門について、様々な記事で扱われている昨今ですが、どれもこれも一部分しか切り取って教えていないものばかりで、結局全体として分かりにくい入門になっているかと思います。
私もUnity+C#で開発する中でようやく本質と思えることが分かったので、
コードなどは一切書かずに概念だけ共有しておきます。
#オブジェクト指向は何を目的としている?
##本質
オブジェクト指向が一番目指したい部分は何かというと、
「責任の所在がどこにあるのかはっきりさせる」
というただこの一点のみだと私は考えています。
会社の例で考えてみる
会社の例を一つ考えてみましょう。
ある事業部に部長と次長、そして平社員がいました。
部長は、新しい予算で新しい設備を買って生産性を上げていこうと考えていて、
「役員に見せる資料を平社員に作らせてね」といった趣旨の指示を出す必要があります。
#手続き型プログラムの抱える問題
さっきのことをプログラム風に考えると、手続き型プログラムはこんな実装になります。
部長「次長くん、平社員A君B君C君に例の見積もり書をこの条件で書いてメリットとどれくらい効率が良くなるかを提出させてね。あとデザイン案はこんな形で。A君は調査、B君は資料印刷、部数は50部で、3階のコピー機使って。C君には見せる資料でパワーポイントを作成させといてねー。はい、よろしく」
次長「はい!やらせておきます。」
##問題発生!!
部長**「次長、ここの数字間違ってるじゃないか!!役員会で恥かいたぞ」**
次長「ええっ・・・」
ここはチェックしない次長が頭悪いとか、そういう話ではありません。プログラム上、命令されていないことはやらないので、すべての数字と内容をチェックする責任は部長と次長になってしまうわけです。
部長「じゃぁ、責任取ってちゃんと最後に全部チェックするからそれでええでしょ? 次長くん任せた!」
そうすれば良いってもんじゃないんです。...っていうのはなんとなくわかるかと思います。
##この部分の致命的な問題点
記載された金額が一桁ずれていて、実は10倍以上費用が掛かることが発覚した場合は、
稟議が通らなかった原因はどこにあるでしょうか?
当然見積もりを間違えて提出した平社員と、それをチェックしていなかった次長か部長が原因...?
いいや、これでは当然ダメですよね。当たり前ですが、これでは原因などわかっていないのと同義です。
実はC言語やその他手続き的処理のプログラムを書いてしまうと、
このようにこの責任がどこにあるのか?という問題が分散しがちです。
なぜでしょうか?
##最終的なミスの責任はだれ??
ここで問題なのは最終チェックをしないからではなくて、なぜ部下が間違えた数字を送ってきたのかをしっかり調査しなければいけないというところです。
ですが、ミスを見つけて、指摘してやろうと思っても実は結果だけ見ても全く意味がないんですね。
よくよく考えればすぐに分かることで、上記のような具合で分担して仕事していたとすると、
A君が資料に記載する数字を間違えたのか、B君がミスを訂正する前のマスター版じゃないものを印刷したのか、C君が誤植したのかまったく分からないんですね。
あるいはB君C君の複合ミスの場合もあります。
もっとまずい例として、部長自身が間違えた指示を出している可能性もあります。
それなのに、結果ありきでまとめて怒られてしまった平社員くんたちは「言ってることがちげぇ!」「自分は何もミスしていないのに・・・」とストレスMAXなわけです。
結果として、ミスの直接的な原因は全く分からず、うやむやになり意味もなく怒って空気悪くしただけです。最悪ですね。
そこで部長は、これじゃいかん!と手続き型の命令をやめて、オブジェクト指向の考え方をしっかり導入することにしました!
#オブジェクト指向を使おう!
オブジェクト指向は、先ほどの例を使えば、
自分がやった仕事は自分で責任を持ちましょう!
ということを目指しています。
ゲッター・セッターの概念導入
A君は受け取った情報を精査し、資料をミスなく作ることに専念します。B君は一度確認し、間違えないようにチェックしながら印刷します。C君も確認してからパワポを作り、最終チェックもします。
オブジェクト指向では全てのInputとOutPutにチェックをつけます。いわゆるゲッター・セッターと呼ばれるものです。これは受け取ったデータをチェックしておかしなデータで処理しないようにするための機構です。
具体的な処理としては、
- A君は受け取った情報と食い違う点、計算がおかしい点などの一通りのチェック
- B君はA君から受け取ったExcelデータ自体がしっかりと印刷すべきデータと合致しているかのチェック
- C君はA君から受け取ったExcelデータとPowerPointが食い違っていないか再度チェック
上記はOutput時のチェック処理になりますが、Input時も本人から間違いのファイルを受け取らないなどのチェックを行います。
これが、いわゆるゲッター・セッターの概念導入です。
public privateの概念導入
もし、調査の結果発覚した原因というのが、
「D君が別の上司に言われたファイルだと思って実はA君のファイルを開いて編集していました。」
という事になった場合、責任はどうなるでしょうか?
当然、これも責任が分散してしまっています。
共有スペースの一番表層でデータやりとりしていたA君にも問題がありますし、
当然間違えたD君も確認しないという点で問題です。
実はプログラミング界ではこんな現実ではあり得ないことがしょっちゅう起こります。
この時導入すべきなのがPublic Privateの概念です。
A君はしっかりとExcelファイルをローカル上で書く事にして、
共有フォルダに入れる際にはファイルに鍵をかけるか、メールで直接送るという方針を立てます。
ファイルに鍵を仕込んだ事によって、ファイルの受け取りミスが100%防げる事になります。
これによって、間違えた場合は責任が確定するわけです。
Publicにしていいものはする。そうでないものはしっかりPrivateにして、いじられない所にしまう。
これだけで、いいんです。
そもそも論としてさ
D君「そもそもですが、なぜA君は資料作成、B君は印刷、C君はパワーポイントをやっているのですか?
A君は不注意だし、A君C君は仲悪いから連携も取れないだろうし、あまりよくないと思いますが。」
こうなるともう大変です。
だって、全て部長が言い出したことなんですから。
そもそもの原因はなんでしょうか? この場合、部長が任せた事になりますね。
でも、普通は中間の次長を挟むべきです。なぜ次長が居るのか。それは次長が平のことをよく知っているのと同時に、
彼らについて責任をもつ立場にあるからです。それを部長が直接話をしてしまっては次長、要らなくなっちゃいます。
オブジェクト指向では責任の分散はNGでしたよね。 ならば、ここも改善しましょう!
カプセル化の実現に向けて
部長「なら、自分は次長に対して部下に稟議を通す準備をお願いするだけでよかったのか。」
そうなんです、部長自らが平たちに指示する必要はないんです。過干渉なんですね。
次長「なら、私が部下に対して、それぞれA君B君C君の3人に期日と内容と実行フローを言い渡し、その進捗管理とチェックの仕事になりますね。」
そして平社員ABCは、それぞれが受け取った内容を全てチェックし、部長や次長などはただ言うだけで全てのチェックが他所からの干渉なく完璧に実行される流れが完成します。
上記のこと全ての流れを、カプセル化と言います。
この状態に至ると、バグの発生原因を容易に特定できる状態が出来上がります。
これはプログラマ界にとって美味しい事だらけなんですね。
それに、こうした**役職(つまりクラス)**による指示形態こそが、
オブジェクト指向の目指すべき責任の切り分けのできる組織体系こそが、
オブジェクト指向プログラミングの本質と言えるのです。
##継承について
オブジェクト指向には継承と言う概念も存在します。
ですが、実は会社ではもう実現できています。
例えば、class:社員と言うクラスがあったとして、部長はここで言う何になりますか??
実は、class:社員を継承したclass:部長と言うクラスになります。いわゆる子クラスってやつです。
ここでの覚えておきたい特徴は、子クラスである部長は、親クラスである社員の全権限を使えますが、
逆に親クラスである社員(つまり平社員)は子クラスである部長の権限を使えないと言う状況が発生します。
理にかなってますね。 だって平に見せちゃいけない機密もあるでしょう。
これによって、機能の切り分けができるため、管理職レベルの機密が漏れた場合に、
どこの責任になるかをある程度絞れる事になります。
あるいは、A君が何らかの行動を行ってやばいことになったとして、
それの指示ができるのが管理職層だけとなれば、やはり責任の切り分けが可能になります。
(例としては、管理職階層のセキュリティルームに平を送りこみ、作業をさせてサーバがポシャったなど)
これが継承の全体像です。(あっさりですが、これだけの事です。)
##ポリモーフィズム(多様性、多態性)
これは、属するクラスによって同じメソッド名なのに違う動きをするプログラムのことを指します。
例えば、「挨拶」と言う機能を持っていたとします。
同じ挨拶メソッドですが、
- A君「おはようございます。」
- 部長「ご苦労様」
- 社長「ごきげんよう」
なんて言う風に、クラスが変わると同じ挨拶ですが、反応が違います。
こういったことをポリモーフィズムと呼びます。
(注意:オーバーロードと似ています!自分も最初間違えて投稿していたのでお詫び申し上げます)
こちらは、責任の切り分けと言うよりも、ミスを無くすと言うのが目的のようにも感じます。
社長用挨拶メソッドなどをいちいち用意すると、プログラミング界ではミスが多発するので、
classが使えるオブジェクト指向では好んで使われます。
##補足:オーバーロード
これは、会社で言えば来た人によって対応を変えると言うような、柔軟性を持たせるための仕組みです。
例えば、平社員同士が「挨拶」と言う機能を持っていたとします。
- A君「オッスオッス!!」 → B君「オッスオッス!!」
- A君「オッスオッス!!」 → 取引先の方「」 → 部長「ちょっとA君こっち来なさい。」
と言う事になりかねません・・・
つまり、部長に対しては、同じ「挨拶」と言う動作でも、相手に合わせてちゃんと挨拶すると言うことが大切です。
プログラミング界でも、これがあるとすっきりとしたコードを書くことができる上、余計なミスを減らすことができます。
また、誰々用の挨拶をしなさい!と一人一人に命令するのもちょっと過干渉気味ですよね?
##補足:オーバーライド
これは、オーバーロードと名前が似ていますが、
子クラスが継承する親クラスのメソッドの機能を一部改変することです。
何のこっちゃ???だと思うので、具体例を出せば、
例えばセキュリティカードだと、class:社員では通れないセキュリティルームも
class:部長なら通れるセキュリティも当然あるかと思います。
その際に、社員のセキュリテイカードメソッドにオーバーライドをかけ、
部長クラスなら通れるように設定するといった具合になります。
補足:ちなみにクラスとインスタンスの違いって?
例えば、田中太郎部長と言う人がいたら
部長がクラスで、田中太郎さんと言う人がインスタンスです。
補足:Staticって何?
例えばclass社員の中にstaticな変数があって、それを変更すると
社内のA君にも、B君にも、田中太郎部長にも変更が効いちゃいます。
具体的な例だと、タイムカードの時間みたいなイメージです。
#いかがでしょうか?
とりあえずオブジェクト指向で登場するほとんどの要素は解説できたのかな。と思います。
皆様の成長の一歩になりますように・・・