この記事は、関数 からの続編です。
この記事は、絵でわかる プログラムとは何か(6)~シンボル~ の一記事です。
この記事のポイント
- 様々なカタチをとれるデータ型のことをオブジェクト型と言う。
- 抽象的なデータ型である、オブジェクト型のデータをオブジェクトと言う。
- オブジェクト型は、より具体化した定義を使って宣言する。
- 全ての要素をオブジェクトとしてとらえる考え方を、オブジェクト指向と言う。
- オブジェクト間の関係を記述するプログラミングをオブジェクト指向プログラミングと言う。
- カプセル化、継承、多態性をオブジェクト指向プログラミングの三大要素と言う。
- カプセル化とは、変数(フィールド)と関数(メソッド)をオブジェクトとしてグループ化し、特にそれらに必要なインタフェース以外を隠蔽すること。
- フィールドやメソッドを合わせてメンバーと言う。
- メンバー名を指定する際、そのメンバーをカプセル化したオブジェクト名から指定するように、名前が限定される範囲のことを名前空間と言う。
- 継承とは、段階的に具体化するオブジェクトが、前段階のオブジェクトからメンバーを引き継ぐこと。さらに継承が何段階にも繰り返される場合を、継承チェーンと言う。
- 多態性とは、前段階のオブジェクトが持つメソッドを、複数の後段階のオブジェクトで、別々にオーバーライド(再定義)できること。
- 実行元のオブジェクトが持っていないメソッドを、他のオブジェクトに託して実行することを、委譲と言う。
オブジェクト(object)
オブジェクト型
オブジェクト型とは、様々なカタチをとれるデータ型のことです。オブジェクト型なら「複数のデータ型をひとまとめにした新たなデータ型」というカタチをとることもできます。
カタチが定められていないということは、具体的なカタチにとらわれないということであり、具体的の反対、つまり抽象的なデータ型と言われます。
オブジェクトとは
整数型のデータが整数、文字列型のデータが文字列であるように、オブジェクト型のデータをオブジェクトと言います。
ただ、オブジェクト型を名乗るだけでは抽象的過ぎて、様々なオブジェクト型のオブジェクトを一様に扱うことはほとんどできません。関数を関数型と名乗っても、抽象的過ぎて、一様に扱えないのと同じです。
関数の宣言で関数リテラルを使うのと同じように、オブジェクトも、より具体化した定義(リテラル)を使って宣言します。
オブジェクト指向プログラミング
抽象的なデータ型であるオブジェクト型を使えば、様々なものをオブジェクトとして表せます。突き詰めれば、プログラムに登場する要素(変数や関数など、メモリ上に記録される意味のあるまとまり)の全てを、オブジェクトとしてとらえることも可能です。
例: 変数オブジェクト、関数オブジェクト、…
このように、プログラムを「オブジェクトの集まり」として考え直し、極論して「様々なオブジェクトへの処理を、順序付けたり、制御したりするのがプログラムなんだ!」と捉える、発想の転換をオブジェクト指向と言います。オブジェクト指向でするプログラミングを、オブジェクト指向プログラミング(Object-Oriented Programming、略してOOP)と言います。
オブジェクト指向に対して、それ以前のプログラミングは、手続き型と呼ばれます。そもそものプロセッサの原理から考えても、プログラムカウンタ毎に、オペコードを実行する「手続き」を、ただひたすら書き連ねていくのがプログラムでした。この時点では、オブジェクトという発想が出てこなかったのも、ごく自然なことでしょう。
高級プログラミング言語が普及し、1つのプログラムのためのソースコードが膨大になり、あふれ返るデータを整理する需要が高まっていった時に、誕生したのがオブジェクト指向でした。
手続き型が動詞(述語)中心の考え方なら、オブジェクト指向は名詞(主語や目的語)中心の考え方です。
例えるなら、何十巻にも及ぶ漫画の全体像を伝える時に、出来事を時系列で語るよりも、登場人物紹介でまとめた方がスッキリするのと同じです。同じ展開の繰り返しよりも、同じキャラの登場の方が、はるかに繰り返しが多いので、まとめ効果が高いのです。
オブジェクト指向プログラミングの三大要素
次に、オブジェクト指向プログラミングの三大要素と言われる、カプセル化、継承、多態性 についてそれぞれ説明していきます。
カプセル化(encapsulation)
オブジェクトは抽象的なデータ型ですが、具体性を持たせるために付け加えられていく要素が、フィールド(field)と呼ばれるデータと、メソッド(method)と呼ばれる関数です。
一つのオブジェクトには、複数種類のフィールドやメソッドを持たせることができます。このように、フィールドとメソッドをひとまとめにすることをカプセル化と言います。
フィールド
そのオブジェクトについてのデータを、変数として扱えるようにしたものです。フィールドには、オブジェクト変数などの参照型も使えます。
メソッド
そのオブジェクトがとる反応(入力に対する出力)を関数にしたものです。通常の関数と同様、メソッドの定義では、引数と戻り値を指定できます。
- 引数・・・メソッドの呼び出し元から、メソッドへの入力
- 戻り値・・・メソッドから、メソッドの呼び出し元への出力
引数や戻り値が省略される場合は、暗にメソッドの親インスタンス自身(this)が、メソッドの入力や出力となります。
メンバー
フィールドとメソッドのことを併せてメンバー(member)と言います。
メンバーは、メンバー名(下の例では▲▲や■■)の前に、オブジェクト名(下の例では●●)とドット(.)をつけて、識別させます。
例えば、
- ●●オブジェクトの、▲▲フィールド ・・・通常、●●.▲▲ と表す
- ●●オブジェクトの、■■()メソッド ・・・通常、●●.■■() と表す
のように指定します。
このように、ドットの前の名前によって範囲を限定した上で、ドットの後ろの名前を識別させる場合、ドットの前の名前を名前空間(namespace)と言います。
「●●フォルダ内の、▲▲ファイル」と指定する時の、フォルダと同じ考え方です。
情報隠蔽
カプセル化という言葉には、「ひとまとめにする」という意味だけでなく、「閉じ込める」という意味合いも含まれます。
例えば、爬虫類オブジェクト内の二つのメンバーを見てみましょう。
例1)細胞総数を表す細胞フィールド
細胞フィールドへ、外部から直接、1,000,000,000,000,000 のような巨大な値を代入
→トカゲがいきなり恐竜のように変身!
例2)空気を吸ったり吐いたりを定期的に繰り返す肺呼吸()メソッド
肺呼吸()メソッドを外部から直接、何度も実行
→爬虫類が過呼吸に!
遊びのプログラムなら、こういうハプニングもアリかもしれませんが、例えば、自然を再現する研究プログラムの実行中に、誤ってこのようなことが起こってしまったら、そのプログラムへの信頼性は、地に堕ちることでしょう。
このように、オブジェクト内部での処理のためだけに作ったフィールドやメソッドを、オブジェクトの外部から実行できなくすることを情報隠蔽(information hiding)と言います。「隠蔽」というと悪いことをしているようですが、「事件を防ぐセキュリティ」と考えるとよいでしょう。
逆に、オブジェクトの外部からも可能な、特定フィールドの読み書きやメソッド実行を、オブジェクトのインタフェース(interface)と言います。
狭義のカプセル化は、「必要なインタフェースだけをオブジェクト外へ公開し、他は情報隠蔽する」という方針に沿ったカプセル化を意味します。
例えるなら、お店として開店中であっても、お客さんが自由に出入りできる店内と、店のプライベートエリアとは、キチンと分ける(盗難や破壊などの営業妨害行為を、簡単にはできなくする)・・・というような考え方です。
プロパティとアクセサ
アクセサ(accessor)と呼ばれるメソッドからのみアクセスできるようにしたフィールドを特にプロパティ(property)と言います。アクセサには、以下の2種類があります。
- フィールドへの代入をするsetter()
- フィールドの値を利用するgetter()
アクセサにチェック機能を持たせることで、より安全にフィールドデータを扱えるようになります。これをデータ隠蔽とも言います。
したがってプロパティは、単なるデータでしかなかったフィールドよりも高機能になります。 例えば、読取専用(変更不可)や読取不可のプロパティが実現できます。
継承(inheritance)
オブジェクト型は、抽象的なデータ型ですが、フィールドやメソッドを付け加えていくことで、オブジェクトに、より具体性を持たせることができます。
多数のフィールドやメソッドを、一つのオブジェクトへ一気に付け加えるのではなく、少しずつ段階を経て付け加えていくことも可能です。前段階で付けられたフィールドやメソッドが、後段階へも、絶えることなく引き継がれていくことを継承と言います。
後段階に進むほど、フィールドやメソッドの数は増えるので、後段階のオブジェクトは、前段階よりも具体化されます。
多態性(polymorphism)
多態性とは、
1つのメソッドが、オブジェクトに応じて、複数(poly)の形態(morph) を持つ特性(ism)
のことです。
【例】両性類の卵生()では卵塊を作り、鳥類の卵生()では固い殻のある卵を産む。
1つのメソッドと言っても、その形態(入出力形式や処理内容)が異なれば、当然、異なるプログラムが必要になります。つまり多態性と言っても、実際には同一のメソッド名を使っているだけで、同一のプログラムではなく、別々のプログラムになります。
本来、後段階の各オブジェクトには、前段階から共通のメソッドが継承されますが、個別に異なる部分だけを、各オブジェクト定義内で上書きできます。これをメソッドのオーバーライド(override = 抑え込み)と言います。
多態性では、このメソッドのオーバーライドにより、同一のメソッド名であってもオブジェクトごとに別々のプログラムを指定することができるのです。
なお、異なるプログラムであっても、同一のメソッド名で使い分けられるのは、名前空間によって「●●オブジェクトの、■■()メソッド」という識別がされるからです。
こうして、同一のメソッド名であっても、オブジェクトに応じて別々の形態をとれるのです。
継承チェーンと委譲
なお、メソッドの継承は、オーバーライドをしない限り、通常は前段階オブジェクトへの参照で実現されます。オーバーライドしていなければ、同じメソッドをオブジェクトの数だけコピーしていくのは、メモリの無駄遣いになるからです。
継承は通常、何段階にもなっていて、前段階オブジェクトから後段階オブジェクトへの継承が繰り返されます。これを継承チェーンと言います。
継承チェーンのどこかに組み込まれたオブジェクトのメソッドを実行する際は、そのオブジェクトでオーバーライドされていなければ、メソッドが見つかるまで継承チェーンを、前段階方向へ遡って見ていくことになります。このように、実行元のオブジェクトが持っていないメソッドでも、他のオブジェクトに託してメソッドを実行することを、委譲(delegation)と言います。継承チェーンは、メソッド実行段階では委譲に利用されるため、委譲チェーンとも言われます。
この記事のまとめ
様々なカタチをとれるデータ型のことをオブジェクト型と言い、
抽象的なデータ型である、オブジェクト型のデータをオブジェクトと言います。
オブジェクト型は、より具体化した定義を使って宣言します。
全ての要素をオブジェクトとしてとらえる考え方を、オブジェクト指向と言い、
オブジェクト間の関係を記述するプログラミングをオブジェクト指向プログラミングと言います。
カプセル化、継承、多態性をオブジェクト指向プログラミングの三大要素と言います。
カプセル化とは、変数(フィールド)と関数(メソッド)をオブジェクトとしてグループ化し、特にそれらに必要なインタフェース以外を隠蔽すること。
フィールドやメソッドを合わせてメンバーと言います。
メンバー名を指定する際、そのメンバーをカプセル化したオブジェクト名から指定するように、名前が限定される範囲のことを名前空間と言います。
継承とは、段階的に具体化するオブジェクトが、前段階のオブジェクトからフィールドやメソッドを引き継ぐこと。
さらに継承が何段階にも繰り返される場合を、継承チェーンと言います。
実行元のオブジェクトが持っていないメソッドを、他のオブジェクトに託して実行することを、委譲と言います。
多態性とは、前段階のオブジェクトが持つメソッドを、複数の後段階のオブジェクトで、別々にオーバーライド(再定義)できること。
次は、オブジェクト(実装編) に進みましょう。
この記事は、絵でわかる プログラムとは何か(6)~シンボル~ の一記事です。
コンピューターのしくみ全体を理解したい場合は、以下の2コースがお勧めです。
日本全国 オンラインレッスン にも対応しています。
知りたいことだけ単発で聞きたい場合は、 オンラインサポート をご利用ください。