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

削除された内容 追加された内容
SUMIM.ST (会話 | 投稿記録)
→‎歴史: 明らかな間違いの修正と補足
タグ: モバイル編集 モバイルウェブ編集
(同じ利用者による、間の7版が非表示)
1行目:
 
{{プログラミング言語|index=おふしえくとしこうふろくらみんく}}
[[ファイル:History of object-oriented programming languages.svg|サムネイル|OOP言語の系譜(水色がOOP)|代替文=|280x280ピクセル|リンク=Special:FilePath/History_of_object-oriented_programming_languages.svg]]
'''オブジェクト指向プログラミング'''(オブジェクトしこうプログラミング、{{Lang-en-short|''object-oriented programming''}}、略語:OOP)は、[[オブジェクト指向]]の[[プログラミングパラダイム|考え方]]<ref>コンピュータ・プログラミングのパラダイムについては『新しいプログラミング・パラダイム』などを参照: http://www.kyoritsu-pub.co.jp/bookdetail/9784320024939</ref>を取り入れた[[プログラミング (コンピュータ)|コンピュータ・プログラミング]]手法である。[[オブジェクト (プログラミング)|オブジェクト]]とは大まかに言うとデータ([[変数 (プログラミング)|変数]]または[[プロパティ (プログラミング)|プロパティ]])とコード([[関数 (プログラミング)|関数]]または[[メソッド (計算機科学)|メソッド]])の複合体を意味してるが、その詳細については様々な解釈が存在する。OOPに基づくプログラムはこの[[オブジェクト (プログラミング)|オブジェクト]]の集合を中心にして組み立てられる事になるが、その実装スタイルもまた千差万別である。
 
OOPの成り立ちにもまた諸説ある。オブジェクト指向プログラミングという言葉自体は、計算機科学者[[アラン・ケイ]]が1972年から80年にかけて公開した[[Smalltalk]]の言語設計を説明する中で初めて生み出されている。なお、データとコードの複合体である[[オブジェクト (プログラミング)|オブジェクト]]という用語を確立したのは1967年公開の[[Simula|Simula67]]であった。[[Simula|Simula67]]の[[クラス (コンピュータ)|クラス]]と[[オブジェクト (プログラミング)|オブジェクト]]の設計及び用法は[[手続き型プログラミング]]の機能拡張に近いものであったが、こちらもOOPの草分けと見なされるようになった。[[Smalltalk]]のプログラム内のあらゆる要素をオブジェクトとして扱い、[[メッセージパッシング]]で相互作用させる本来の意味でのオブジェクト指向設計は、哲学的かつ理論偏重のきらいがあったので実践面ではさほど広まらなかった。1983年に公開された[[C++]]が契機となり、OOPはまた違った角度から注目されるようになった。最終的にこの[[C++]]の設計スタイルが物議を醸しながらもOOPの主流となるに到り、同時にOOPの三大原則とされる[[カプセル化]]、[[継承 (プログラミング)|継承]]、[[ポリモーフィズム|多態性]]の[[プログラミングパラダイム]]が確立されている。
 
== 特徴 ==
プログラミングパラダイムとしてのオブジェクト指向の確立は紆余曲折を経ており(後述)その詳細の解釈も様々であるが、一定の枠組みとなる三つの原則仕様(''fundamental principle'')が存在する。この三原則に従った言語仕様を総体的または部分的に備えたプログラミング言語がオブジェクト指向準拠と判別される。1~3はいわゆるOOPの三大原則とされるものであり、[[C++]]を契機にして確立提唱された。4はオブジェクト指向プログラミングという用語の発端となった[[Smalltalk]]設計の主軸であるが、現在では亜流となっている。
 
#[[カプセル化]](''encapsulation'')
27行目:
; カプセル化
 
従来のプログラミング環境では、動作を定義表現するコード(関数)状態を表現するデータ(変数)扱う操作する形でプログラムを記述されるのが一般的だったが、開発規模の拡大に伴い解決の難しいソフトウェアバグ原因の大半は、データの予期せぬ変動と各データ間の不整合である事が経験則で知られるようになって来た。そこでデータを中心にしてプログラムを組み立てようとする考え方が生まれ、その目的に沿うものとしてデータとコードの複合体であるオブジェクトに白羽の矢が立てられた。オブジェクト内のデータは基本的に同じオブジェクト内のコードだけが参照または変動可能とする仕組みが考案され、これがカプセル化と呼ばれた。データを変動させたコード位置の把握を容易にする為に、各データにアクセス出来るコードの範囲を厳密に定めたカプセル化の機能は、範囲外アクセスをコンパイルレベルで禁止して想定外のデータ変動をもたらす人的ミスを減らした。また、データを変動させるコードを呼び出すそのまたコード位置の把握も芋蔓式に必要となったのでコードにもアクセス範囲が定められる様になり、た。更にアクセス範囲の広さにも段階がけられたので特定の外部をも含んだ柔軟な内部隠蔽の設が可能となった。
 
カプセル化を推し進めたものとして'''プロトコル'''(''protocol'')がある。これはオブジェクトの構成要素を全隠蔽し、外部アクセス可能な要素だけを抜き出してまとめたものを、純粋抽象クラスまたは界面オブジェクトとして公開する仕組みを指す。仕組み的に外部公開される要素はメソッドに限られ、データもそれ専用のメソッドを通して参照ないし変動される。プロトコルは後述の多態性にも関連しており、特に動的ディスパッチを表現するメカニズムにもなった。多くのプログラミング言語ではインターフェースの名で知られているものである。
 
; 継承
 
プログラム内の膨大な数のデータは通常グループ化(構造体)されて扱われていたが、複数の構造体間にまたがる共通のデータ集合が数多く目に付くようになり、その冗長さと整合性の問題が浮き彫りとなっていた。これを解決する為に構造体=オブジェクトを複数の'''階層要素'''に分け、共通のデータ集合を親階層とし、派生する子階層に親階層の参照アドレスを持たせて連結する構造が考案された。A階層から成る親オブジェクトから派生した子オブジェクトはA+B階層として構成され、これが継承と呼ばれた。コードから参照されたデータがB階層に無い時は、次のA階層に有るか探す仕組みとなり、この連鎖によって傍からは一つのオブジェクトとして存在した。なおデータと同様に共通のメソッド集合も親階層にまとめられた。その応用として後述の仮想関数と同義である抽象メソッド集合だけの階層を独立させたインターフェースまたは純粋抽象クラスがありこれを親階層として継承(実装)する行為は'''[[派生型|サブタイピング]]'''(''subtyping'')となった。サブタイピングは後述の多態性のメカニズムの一つでもある。なお、継承クラスで任意の機能を追加出来る継承は従来コードの再利用性を高めるとも考えられたが、深い継承がもたらす構成把握の難化が問題視されてほぼ否定された。これ継承による再利用性はクラスライブラリの使用内に留まっている。{{いつ範囲|date=2019年2月|現在}}では深い継承は倦厭される様になり、代わりに仮想メソッドテーブル(Java''interface''など)を実装させる横に長い継承重視されている。また、クラスのメカニズムをベースとするOOP言語現状は多態性を実現する為の手段として用いられている。
 
なお、子階層の次のリンク先となる親階層は一本だけでなく複数本持つ事も出来るので、複数の親階層+子階層によるオブジェクト構成は'''多重継承'''と呼ばれた。子階層が持つ親階層アドレスは一般にリスト化されており、自身に無いデータはリスト先頭の親階層から順々に検索された。その親階層が多重継承されてる場合も同様であり、それぞれの枝分かれには深さ優先検索が用いられた。前述のサブタイピングは多重で行われる事が多い。
 
; 多態性
39 ⟶ 43行目:
パラメータ多態性もソースコードの記述を一部自動化するものである。関数内またはクラス内の型指定部分をワイルドカードにして宣言しておき、ソースコード内で関数またはクラスが実装記述されると、その具体的な型指定を関数内またはクラス内のワイルドカードに当てはめたコード部分がコンパイル時に自動生成されるという機能だった。前者は'''ジェネリック関数'''と呼ばれ、後者はより広い範囲を扱う事から'''ジェネリックプログラミング'''と名付けられた。これらも静的な多態性に位置付けられている。
 
サブタイプ多態性は動的なものである。最も初期のOOPであるSimula67は、シミュレーション内で扱う多種多様なオブジェクトを継承によって体系化したが、コード部分の細かな違いは共通スーパークラスに属する共通プロシージャ内の分岐フローで処理していた。サブクラスの数だけ分岐構文が増える頻雑さを解消する為に、共通プロシージャをただの住所テーブルにしてサブクラスの実装時に同名プロシージャのアドレスを収納させ、共通プロシージャ呼び出し時そのアドレスへジャンプするという機能が考案された。住所テーブルと化した共通プロシージャは仮想的存在と見なされたので、これがの機能は'''仮想関数'''となっ呼ばれた。'''動的ディスパッチ'''はSmalltalkのオブジェクト設計に由来するものであり、その実装の仕方は様々でやや曖昧な仕様でもある。メッセージを受け取ったレシーバーがオブジェクト内部で動的な状態に従い動的な処理を行って結果を返すというランタイム環境上のプロセスが後に動的ディスパッチのカテゴリで括られた。遠隔プロセスを扱うリモ[[分散コンピュティング]]を表現する[[Object Request Broker|オブジェク間通信]]とそれに基づく[[ッドのシステムフトウェアコンポーネント]]も動的ディスパッチに該当するものである。仮想関数および動的ディスパッチと同義に扱われる用語に'''[[動的束縛|遅延バインディング]]'''(''late binding'')があるが、これはより幅広い意味を含みOOP外でも用いられる言葉である。'''多重ディスパッチ'''は動的な関数オーバーロードに近いものである。関数コール時または関数ブロック内で、それぞれの引数が動的に型審査されて型変化(''dynamic casting'')された後に、その引数パターンに対応した同名関数または分岐ルーチンに処理が移行されるという動的変化プロセスを指した。'''ダブルディスパッチ'''は多重ディスパッチの亜流またはその派生物的存在であり、二通りの考え方がある。動的型審査および型変化されるBオブジェクトを単一引数にしてAオブジェクトの仮想関数メソッドを呼び出す形態と、多重ディスパッチに用いる引数を二つに限定した形態である。いずれも実行時状態に応じた動的変化プロセスとなった。これは主にデータ集合を対象にして分類、解析、作用といった処理を連続的または再帰的に行うアルゴリズムで用いられた。
 
; メッセージパッシング
45 ⟶ 49行目:
これは従来のパラメータ付きサブルーチン呼出とリターン値のやり取りを別の視点から再解釈したのであり、基本はバイトデータ(メッセージ)の送受信でセレクタ(メソッド名)とパラメータ、そしてリターン値をやり取りする仕組みだった。オブジェクトのレシーバー(代表メソッド)が渡されたメッセージを解釈し、オブジェクト内部でそれに準じた処理を行い、結果をリターンした。パラメータとリターン値もまたオブジェクトだったので、リターン値をメッセージ内のパラメータにして後続のオブジェクトへ送る事もでき、そのリターン値にまた別のメッセージを送る事も出来た。Smalltalk設計では真偽値、数値、コードブロックもオブジェクトとなったので、真偽値または数値に対して規定の予約語(セレクタ)と併せたコードブロックをメッセージとして送る事で条件分岐や反復処理といった制御フローを表現出来た。オブジェクトを次々とメッセージとして送るのは順次処理となった。メッセージパッシングとは、オブジェクトにオブジェクトを引き合わせて、双方に関連した手続きまたは制御フローを発生させるルーチンワークを意味しており、この連鎖的かつ再帰的な繰り返しがプログラム全体の流れとなった。この斬新なパラダイムを実際のプログラムの形にする為には比較的緻密な設計が要求され、またパターン化されたプロセスにおいても柔軟さを維持する為のワンステップを必要とするので開発工数とCPU負荷が増大する欠点もあった。これが倦厭されてOOP設計の本質でありながら広くは支持されず、OOPに対する関心の焦点は本来は枝葉の部分であるはずのクラスのメカニズムに移る事になった。
 
Smalltalkの影響を受けた後継言語においても、あらゆるプログラム要素をメッセージで表現しようとする理論の追求は避けられ、例えば制御フローは制御構文で扱われている。またメッセージングに対する認識もシフトし、オブジェクトの代表となるメソッドがパラメータを受け取り多様な処理と移譲を行ういわゆるレシーバーの仕組み自体がメッセージングそのものと見なされるようになった。そのメカニズムを応用したリモー[[Object Request Broker|オブジェクメソッド間通信]]を実現するバイトデータの送受信もメッセージパッシングの代表例となった。また、オブジェクトのメソッドコールもメッセージと定義する見解も出たが、これは同時に物議を醸している。この様にメッセージパッシング設計の本質は見失われながらも、その側面的仕様は数々のOOP言語に導入されてもいる。
 
== 歴史 ==
113 ⟶ 117行目:
'''[[Ceylon]]''' 2011年
:[[Java]]を元に開発され、その長所と短所を見直しつつ再設計されたOOP言語。Javaの改造版である。また[[JavaScript]]にもコンバートできる。
 
'''[[Kotlin]]''' 2011年
 
: [[Javaバイトコード]]を出力し、[[Java仮想マシン]]上で動作するJVM互換のOOP言語。オブジェクト指向プログラミングと関数型プログラミングの併用が指向されている。前者は全体的な枠組みに、後者は細部の実装に適しているとされる。
 
[[Swift (プログラミング言語)|'''Swift''']] 2014年