「オブジェクト指向プログラミング」の版間の差分

削除された内容 追加された内容
編集の要約なし
タグ: 2017年版ソースエディター
(同じ利用者による、間の8版が非表示)
8行目:
'''オブジェクト指向プログラミング'''(オブジェクトしこうプログラミング、{{Lang-en-short|''object-oriented programming''}}、略語:OOP)は、[[オブジェクト指向]]の[[プログラミングパラダイム|考え方]]<ref>コンピュータ・プログラミングのパラダイムについては『新しいプログラミング・パラダイム』などを参照: http://www.kyoritsu-pub.co.jp/bookdetail/9784320024939</ref>を取り入れた[[プログラミング (コンピュータ)|コンピュータプログラミング]]手法である。[[オブジェクト (プログラミング)|オブジェクト]]とは大まかに言うとデータ([[変数 (プログラミング)|変数]]または[[プロパティ (プログラミング)|プロパティ]])とコード([[関数 (プログラミング)|関数]]または[[メソッド (計算機科学)|メソッド]])の複合体を意味してるが、その詳細については様々な解釈が存在する。OOPに基づくプログラムはこの[[オブジェクト (プログラミング)|オブジェクト]]の集合として組み立てられる事になるが、その実装スタイルもまた千差万別である。
 
オブジェクト指向プログラミングという言葉自体は計算機科学者[[アラン・ケイ]]が作り出したものである。彼は1967年に公開された[[Simula|Simula67]]の[[クラス (コンピュータ)|クラス]]と[[オブジェクト (プログラミング)|オブジェクト]]を備えた言語仕様を見た際に''object-orientedという咄嗟の造語を咄嗟に口にしたという''。され、その造語は''ケイ自身が1972年から80年にかけて開発した[[Smalltalk]]の言語設計を説明する中で初めて発信さ用いられて世間に知られるようになった。なお、[[Smalltalk]]のあらゆるプログラム内要素をオブジェクトとして扱い、[[メッセージパッシング]]で相互作用コミュニケーションさせるという元祖オブジェクト指向は、哲学的かつ理論偏重のきらいがあったので実践面ではさほど広まらなかった。1983年に公開された[[C++]]が契機となり、OOPはまた違った角度から注目されるようになった。最終的にこの[[C++]]の設計スタイルが物議を醸しながらもOOPの主流となるに到り、同時にOOPの三原則とされる[[カプセル化]]、[[継承 (プログラミング)|継承]]、[[ポリモーフィズム|多態性]]の[[プログラミングパラダイム]]が確立されている。
 
== 特徴 ==
プログラミングパラダイムとしてのオブジェクト指向の確立は紆余曲折を経ており(後述)その詳細の解釈も様々であるが、一定の枠組みとなる三つの原則(''fundamental principle'')が存在し、それに従った言語仕様を総体的または部分的に備えたプログラミング言語がオブジェクト指向準拠と判別される。1~3はオブジェクト指向プログラミングの三原則とされるものであり[[C++]]を契機にして提唱された。また、4~6は[[Smalltalk]]が提唱する元祖オブジェクト指向の三骨子(''essential ingredient'')とされるが現在では亜流となっている
 
4~6は[[Smalltalk]]が提唱する元祖オブジェクト指向のコンセプトであり、この三者は相互に関連して始めて一つの意味を表現している。その真髄はオブジェクトを媒体にしてコードとデータの融合を目指した高度な抽象化または代数化である。元祖オブジェクト指向は哲学的側面が強いものであり、それを実用的に演繹したものが1~3であると考える事も出来る。
 
#[[カプセル化]](''encapsulation'')
27 ⟶ 29行目:
#**[[ダブルディスパッチ]](''double dispatch'')
#**[[多重ディスパッチ]](''multiple dispatch'')
#[[メッセージ (コンピュータ)|メッセージパッシング]](''message passingmessaging'')
#ローカル保持(''local retention, protection, hiding of state-process'')
#[[動的束縛|遅延バインディング]](''late binding'')
44 ⟶ 46行目:
アドホック多態性は単にソースコードの記述を一部自動化するものである。'''関数オーバーロード'''は引数の並び方パターンによって同じ名前のメソッドをコンパイル時に自動的に差別化する機能である。'''演算子オーバーロード'''は、扱う数値の型に従って宣言された演算記号を関数名と見なすようにし、単項演算子なら右の数値を第一引数とし、二項演算子なら左右の数値をそれぞれ第一第二引数として関数呼び出しのコードが生成されるという仕組みだった。丸括弧の演算子は関数オブジェクトの表現として使用出来た。これらは静的な多態性とされる。
 
パラメータ多態性もソースコードの記述を一部自動化するものである。関数&クラスのコード内の特定の型部分をワイルドカードにして記述しておき、ソースコード内で具体的な型の指定と共に関数&クラスの呼び出しが記述されると、その型を先のワイルドカードに当てはめた関数&クラスのコードがコンパイル時に自動生成されるという機能だった。&の前者は'''ジェネリック関数'''と呼ばれ、後者はより広い範囲を扱う事から'''ジェネリックプログラミング'''と名付けられた。これらも静的な多態性に位置付けられている。
 
サブタイプ多態性は動的なものである。最も初期のOOPであるSimula67は、シミュレーション内で扱う多種多様なオブジェクトを継承によって体系化したが、コード部分の細かな違いは共通スーパークラスに属する共通プロシージャ内の分岐フローで処理していた。サブクラスの数だけ分岐構文が増える頻雑さを解消する為に、共通プロシージャをただの住所テーブルにしてサブクラスの実装時に同名プロシージャのアドレスを収納させ、共通プロシージャ呼び出し時にそのアドレスへジャンプするという機能が考案された。住所テーブルと化した共通プロシージャは仮想的存在と見なされたので、この機能は'''仮想関数'''と呼ばれた。'''動的ディスパッチ'''はSmalltalkのオブジェクト設計に由来するものであり、その実装の仕方は様々でやや曖昧な仕様でもある。メッセージを受け取ったレシーバーがオブジェクト内部で動的な状態に従い動的な処理を行って結果を返すというランタイム環境上のプロセスが後に動的ディスパッチのカテゴリで括られた。[[分散コンピューティング]]を表現する[[Object Request Broker|オブジェクト間通信]]とそれに基づく[[ソフトウェアコンポーネント]]も動的ディスパッチに該当するものである。'''多重ディスパッチ'''は動的な関数オーバーロードに近いものである。関数コール時または関数ブロック内で、それぞれの引数が動的に型審査されて型変化(''dynamic casting'')された後に、その引数パターンに対応した同名関数または分岐ルーチンに処理が移行されるという動的変化プロセスを指した。'''ダブルディスパッチ'''は多重ディスパッチの亜流的存在であり、二通りの考え方がある。動的型審査および型変化されるBオブジェクトを単一引数にしてAオブジェクトの仮想関数メソッドを呼び出す形態と、多重ディスパッチに用いる引数を二つに限定した形態である。いずれも実行時状態に応じた動的変化プロセスとなった。これは主にデータ集合を対象にして分類、解析、作用といった処理を連続的または再帰的に行うアルゴリズムで用いられた。
 
=== メッセージパッシング ===
メッセージングは哲学的側面が強いパラダイムである。仕組み的には、オブジェクト(=インスタンス)のメソッドコール、または[[Object Request Broker|オブジェクト間通信]]におけるリモートメソッドコールと同じものと考えてよいが、メッセージングのパラダイム下では、イメージ的にオブジェクトそのものをメソッドとしてコールする点が異なっている。それは各オブジェクトが一般にレシーバーと呼ばれるデフォルトメソッドを持つ事で実現されている。オブジェクトのコールとは、このレシーバーをコールするのと同義となる。引数無しでコールされる事はなく、基本的に一つのオブジェクトが引数となってコールされる。元祖オブジェクト指向では「''EverythingIsAnObject''」の通り、[[プリミティブ型|プリミティブ]]から[[構造体|データストラクチャ]]、[[コードブロック]]まであらゆるプログラム要素がオブジェクトとされる。ここにオブジェクトA、Bがあるとすると、メッセージングの基本構文は「A B」のようになる。これは「Bを引数にしてAを呼び出す」の意味であり、イメージ的に「Aに対してBというメッセージを送る」と形容される。引数Bを受け取ったAのレシーバー内で任意の処理が行われた後に結果値としてのオブジェクトが返される。Aそのものが返される事もあれば、別のオブジェクトが返される事もある。この流れがメッセージングと呼ばれるものである。返値オブジェクトに対して別のメッセージを送る事も可能であり、また返値オブジェクトをメッセージにして別のオブジェクトに送る事も出来る。こうしたメッセージングの連鎖はAのレシーバー内でも同様に行なわれる。メッセージング・パラダイム下でのオブジェクトは言わば独自の記憶を備えた変換式であり、これらオブジェクトのコミュニケーションとは[[高階関数]]と[[第一級関数]]の仕組みと同じものである。メッセージング・パラダイムの本質はオブジェクトの代数化(''algebraization'')であり、その代数値は前述のメッセージングの連鎖による結果値である。メッセージングを行なうオブジェクトもまたメッセージング連鎖の集合体という事になる。それはただの[[プリミティブ|プリミティブ値]]であっても場合によっては例外でない。レシーバーでの処理をコードとすると、メッセージング・パラダイム下でのデータはメッセージング連鎖によるコードの集合体であり、そのコードは他のデータ群を参照しており、その各データもまたコードの集合体~という風になる。こうなるとイメージ的にコードとデータが融合して両者の区別がなくなる。同時にこのメカニズムは、オブジェクトがメッセージを受け取った時に始めて一定のプロセスが発生し、または一つのデータが体現されるという環境を提供する。
これは元々は、式指向(''expression-oriented'')プログラミングまたは関数型プログラミングで用いられていた[[高階関数]]の仕組みを[[参照透過性]]と相反する観点から独自に拡張させたパラダイムだった。この視点の下では、変換式に独自の記憶を持たせたものがオブジェクトとなり同時に多態性の表現に繋がった。なお、メッセージパッシングとは如何なる形態であれ、オブジェクトの動作の呼び出しを行うという一点で共通している。その仕組みの基本は関数と同様にパラメータ値付きメソッド名(セレクタ)とリターン値をやり取りする事であり、これがスタックエリアなどを通したサブルーチンコール形態ではなく、バイトデータ羅列の受け渡しで行なわれる場合は[[Object Request Broker|オブジェクト間通信]]に近いものとなった。メッセージパッシングとしての特徴は、パラメータ値とリターン値もそのままオブジェクトとなる事であり、得られたリターン値オブジェクトのメソッドを呼び出してそのまたリターン値を取得し、そのリターン値を別のオブジェクトメソッドを呼び出す為のパラメータ値オブジェクトに出来るといったオブジェクトメソッド呼び出しの連鎖動作が可能な点であった。メッセージパッシング=オブジェクトの相互作用と称される本来のスタイルはこの様なものである。
 
なお、実装面では便宜上の理由から、メッセージングの際の引数オブジェクトにはセレクタを付けるのが許容されている。大抵は「A ''selector'':B」の様になる。セレクタはメソッド名と同義であり、引数オブジェクトに貼られるラベルと考えていいものである。セレクタによってレシーバー外の対応メソッドに自動分岐されるのでコーディングが簡便になる。[[演算子]]も事実上のセレクタであり「5+3」は、+セレクタを貼った3オブジェクトを5に送ると解釈できる。括弧記号はコンパイラの為のただの[[ディレクティブ]]となる。メッセージングは二つのオブジェクトが出会った時点で発生するプロセスなので引数は常に一つであり、複数の引数を用いたい場合はパーシャルアプリケーションまたは[[カリー化]]を適用するべきであるが、これは困難なコーディングになる事が多いので、セレクタによる[[パターンマッチング]]的な各メソッドへの自動分岐も許容されている。
Smalltalk設計では真偽値、数値、コードブロックもオブジェクトとなったので、真偽値または数値に対して規定の予約語(セレクタ)と併せたコードブロックをメッセージとして送る事で、条件分岐や反復処理といった制御フローをもオブジェクトによる相互作用の形態で表現可能だった。オブジェクトを次々とメッセージとして送るのは順次処理となった。メッセージパッシングとは、オブジェクトにオブジェクトを引き合わせて、双方に関連した手続きまたは制御フローを発生させるルーチンワークを意味しており、この連鎖的かつ再帰的な繰り返しがプログラム全体の流れとなった。この斬新なパラダイムを実際のプログラムの形にする為には比較的綿密な設計が要求され、またパターン化されたプロセスにおいても柔軟さを維持する為のワンステップを必要とするので開発工数とCPU負荷が増大する欠点もあった。これが倦厭されてOOP設計の本質でありながら広くは支持されず、OOPに対する関心の焦点は本来は枝葉の部分であるはずのクラスのメカニズムに移る事になった。
 
Smalltalk影響を受けた後継言語においても、あらゆるプログラム要素をメッセージで表現しようとする理論ング追求パラダイム避け様々な理由か広くは認知さ例えば制御フローは制御構文で扱われやがその言葉だけが一人歩きす。またメッセージングよう対する認識もなって本来の定義からシフトし、オブジェクト前述代表となるメソッドがパラメータを受け取り多様な処理と移譲を行ういわゆるレシーバーの仕組み自体がメッセージングそのものと見なされるようにった。そのメカニズムを応用したり、[[Object Request Broker|オブジェクト間通信]]を実現すで行なわれるバイトデータの送受信もメッセージパッシングの代表例とされるようになった。また、オブジェクトインスタンスの単純なメソッドコール自体呼び出しもメッセージングである定義す説明され見解出たが、これは同時に物議を醸している。この様にメッセージパッシング設計の本質は見失われながらも、その側面的仕様は数々のOOP言語に導入されてもいる。
 
=== ローカル保持 ===