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

削除された内容 追加された内容
編集の要約なし
(同じ利用者による、間の2版が非表示)
11行目:
 
== 特徴 ==
プログラミングパラダイムとしてのオブジェクト指向の確立は紆余曲折を経ており(後述)その詳細の解釈も様々であるが、一定の枠組みとなる三つの原則(''fundamental principle'')が存在し、それに従った言語仕様を総体的または部分的に備えたプログラミング言語がオブジェクト指向準拠と判別される。1~3はオブジェクト指向プログラミングの三原則とされるものであり[[C++]]を契機にして提唱された。4を加えて四本の柱(''pillar'')とする考えもある
 
4~65~7は[[Smalltalk]]が提唱する元祖オブジェクト指向のコンセプトであり、この三者は相互に関連して始めて一つの意味を表現している。その真髄はオブジェクトを媒体にしてコードとデータの融合を目指した高度な抽象化または代数化である。元祖オブジェクト指向は哲学的側面が強いものであり、それを実用的に演繹したものが1~3であると考える事も出来る。
 
#[[カプセル化]](''encapsulation'')
29行目:
#**[[ダブルディスパッチ]](''double dispatch'')
#**[[多重ディスパッチ]](''multiple dispatch'')
#[[抽象化 (計算機科学)|抽象化]](''abstraction'')
#[[メッセージ (コンピュータ)|メッセージング]](''messaging'')
#ローカル保持(''local retention, protection, hiding of state-process'')
34 ⟶ 35行目:
 
=== カプセル化 ===
従来任意データ(変数、プログラムはパティ)群と動作それ表現参照ないし変更するコードが状態(関数、メソッド)群表現するひとまとめにしてオブジェクトとし、オブジェクト内のデータを操作する形群は外部からはアクセス記述きず隠蔽され、外部公開されたコードを通してみアクセス可能にした仕組み一般的カプセル化と呼ばれる。より詳しい解釈については様々ったが、オブジェクト指向におけるカプセル化は、基本的に内部隠蔽に焦点を当てたパラダイムである。開発規模の拡大に伴い解決の難しいソフトウェアバグ原因の大半は、データの予期せぬ変とデータ予期せぬ不整合である事が経験則で知られるようになって来。そこデータを中心にしてプログラムを組み立てようとする考え方が生まれその目的に沿うものとしてデータとコードの複合体であるオブジェクトに白羽の矢が立てられた。データを変動させたコード位置特定を容易にする為の手段だっめに、オブジェクト内のデータは基本的に同じオブジェクト内のコードだけが直接参照またの禁止変動可能と予期せぬデータの読み取りを抑止する仕組みが考案されだけでなくこれがカプセルいわゆる抽象と呼ばれの一手段も兼ねていた。データを読み取る際ワンセス出来るッションの仲介コードを置く事で実行環境範囲を厳密変化定め合わせカプセル化の機能は、範囲外アクセスをコンパイルレベルで禁止して想定外の柔軟なデータ変動表現もたらす人的ミスを減ら可能にした。、データを変動させるだしこのワンクッション制度は安全性と引き換えにコード記述量呼び出大きくまたコで、特定のデド位置の把握も芋蔓式に必要なったので、コードに対しては便宜的に直接アクセス許可範囲が定めらを解禁する仕組みも生また。更に、これはアクセス範囲の広さにも段階がつけら権限と呼ば、特定の外部をも含んだ柔軟な内部隠蔽の設定が可能となった。
 
カプセル化を推し進めたものとして'''プロトコル'''(''protocol'')がある。これはオブジェクトの構成要素内部を全隠蔽し、外部アクセス可能な要素だけ抽象メソッド抜き出してまとめたものを、純粋抽象クラスまたは界面で表現されるインターフェース・オブジェクトを通して公開アクセスする仕組みを指した。仕組み的に外部公開される要素はメソッドに限られ、データもオブジェクトれ専用メソものにワンクション通して参照なし変動された制度とも言える。プロトコルは同時にオブジェクトの安全な公開にも繋がりを実現し、共同開発とコンポーネント開発に適したものとされた。プロトコルは後述の多態性にも関連しており、特に動的ディスパッチを表現するメカニズムにもなった。多くのプログラミング言語ではインターフェースの名で知られているものである
 
=== 継承 ===
プログラム内継承膨大な数元々データ趣旨通常グループオブジェクトの体系(構造である。ここでの)さ系化とは多様な要素をそて扱わていたが、複数共通と特有分節造体間またがるし、共通部分から特有部分を派生させる形で関連付ける枝葉状データ集合が数多く目展開構図付く投影する行為を指した。構造体の定義増加で発生しやすい似たようり、そデータ群重複に伴う冗長さとその整合性維持問題が浮き彫りとなっていた。これ手間隙を解決する為の手段であっめに構造体=オブジェクトを複数の階層要素に分け、共通のデータ集合を親階層とし、特有のデータ集合を子階層として、子階層に親階層アドレスリンクを持たせて連結する構造が考案されにした。A階層から成る親オブジェクトから派生した子オブジェクトはA+B階層として構成され、これが継承と呼ばれた。コードから参照されたデータがB階層に無い時は、次のA階層に有るか探す仕組みとなり、この連鎖によって傍からは一つのオブジェクトとして存在した。データと同様に共通のメソッド集合も親階層にまとめられた。その応用として後述の仮想関数と同義である抽象メソッド集合(=仮想関数)だけの階層を独立させたインターフェースまたは純粋抽象クラスがあり、これを親階層として継承(実装)する行為は'''[[派生型|サブタイピング]]'''(''subtyping'')となった。サブタイピングは後述の多態性のメカニズムの一つでもある。なお、継承派生クラスで任意の機能を追加出来でき継承仕組み従来コードの再利用性を高めるとも考えられたが、深い継承がもたらすはクラス造の把握を困にするという欠点問題視さ明らかになったのでこてほぼ否定された。継承による再利用性はクラスライブラリの使用範囲内に留まっているのが現状である。
 
なお、子階層の次のリンク先となる親階層は一本だけでなく複数本持つ事も出来るので、複数の親階層+子階層によるオブジェクト構成は'''多重継承'''と呼ばれた。子階層が持つ親階層アドレスは一般にリスト化されており、自身に無いデータはリスト先頭の親階層から順々に検索された。その親階層が多重継承されてる場合も同様であり、それぞれの枝分かれには深さ優先検索が用いられた。前述のサブタイピングは多重で行われる事が多い。
48 ⟶ 49行目:
パラメータ多態性もソースコードの記述を一部自動化するものである。関数&クラスのコード内の特定の型部分をワイルドカードにして記述しておき、ソースコード内で具体的な型の指定と共に関数&クラスの呼び出しが記述されると、その型を先のワイルドカードに当てはめた関数&クラスのコードがコンパイル時に自動生成されるという機能だった。&の前者は'''ジェネリック関数'''と呼ばれ、後者はより広い範囲を扱う事から'''ジェネリックプログラミング'''と名付けられた。これらも静的な多態性に位置付けられている。
 
サブタイプ多態性は動的なものである。最も初期のOOPであるSimula67は、シミュレーション内で扱う多種多様なオブジェクトを継承によって体系化したが、コード部分の細かな違いは共通スーパークラスに属する共通プロシージャ内の分岐フローで処理していた。サブクラスの数だけ分岐構文が増える頻雑さを解消するために、共通プロシージャをただの[[仮想関数テーブル|住所テーブル]]にしてサブクラスの実装時に同名プロシージャのアドレスを収納させ、共通プロシージャ呼び出し時にそのアドレスへジャンプするという機能が考案された。[[仮想関数テーブル|住所テーブルと化した共通]]はプロシージャ仮想的存在と見なされたので、この機能は'''仮想関数'''と呼ばれた。'''動的ディスパッチ'''はSmalltalkのオブジェクト設計に由来するものであり、その実装の仕方は様々でやや曖昧な仕様でもある。メッセージを受け取ったレシーバーがオブジェクト内部で動的な状態に従い動的な処理を行って結果を返すというランタイム環境上のプロセスが後に動的ディスパッチのカテゴリで括られた。[[分散コンピューティング]]を表現する[[Object Request Broker|オブジェクト間通信]]とそれに基づく[[ソフトウェアコンポーネント]]も動的ディスパッチに該当するものである。'''多重ディスパッチ'''は動的な関数オーバーロードに近いものである。関数コール時または関数ブロック内で、それぞれの引数が動的に型審査されて型変化(''dynamic casting'')された後に、その引数パターンに対応した同名関数または分岐ルーチンに処理が移行されるという動的変化プロセスを指した。'''ダブルディスパッチ'''は多重ディスパッチの亜流的存在であり、二通りの考え方がある。動的型審査および型変化されるBオブジェクトを単一引数にしてAオブジェクトの仮想関数メソッドを呼び出す形態と、多重ディスパッチに用いる引数を二つに限定した形態である。いずれも実行時状態に応じた動的変化プロセスとなった。これは主にデータ集合を対象にして分類、解析、作用といった処理を連続的または再帰的に行うアルゴリズムで用いられた。
 
=== 抽象化 ===
純粋抽象クラスの仕組みがこれに相当する。実例としては[[ソフトウェアコンポーネント]]及び[[Java]]などのプログラミング言語で用いられている[[インタフェース (抽象型)|インターフェース]]がある。この抽象化は、カプセル化の{{仮リンク|.プロトコル|en|Protocol (object-oriented programming)|label=}}、継承の[[派生型|サブタイピング]]、多態性の仮想関数をまとめたパラダイムと考える事が出来る。
 
[[C++]]開発者の[[ビャーネ・ストロヴストルップ]]は、広義のオブジェクト指向の主要サポート案件として抽象化、継承、実行時多態性(''run-time polymorphism'')の三点を挙げていた。抽象化は同時に完全な内部隠蔽になるので、コンクリートクラスの中途半端な内部隠蔽ではなく、純粋抽象クラスのプロトコルを重視していた事が分かる。
 
=== メッセージング ===
メッセージングは哲学的側面が強いパラダイムである。仕組み的には、オブジェクト(=インスタンス)のメソッドコール、または[[Object Request Broker|オブジェクト間通信]]におけるリモートメソッドコールと同じものと考えてよいが、メッセージングのパラダイム下では、イメージ的にオブジェクトそのものをメソッドとしてコールする点が異なっている。それは各オブジェクトが一般にレシーバーと呼ばれるデフォルトメソッドを持つ事で実現されている。オブジェクトのコールとは、このレシーバーをコールするのと同義となる。引数無しでコールされる事はなく、基本的に一つのオブジェクトが引数となってコールされる。これも留意すべき点である。元祖オブジェクト指向では「''EverythingIsAnObject''」の通り、[[プリミティブ型|プリミティブ]]から[[構造体|データストラクチャ]]、[[コードブロック]]まであらゆるプログラム要素がオブジェクトとされる。ここにオブジェクトA、Bがあるとすると、メッセージングの基本構文は「A B」のようになる。これは「Bを引数にしてAを呼び出す」の意味であり、イメージ的に「Aに対してBというメッセージを送る」と形容される。引数Bを受け取ったAのレシーバー内で任意の処理が行われた後に結果値としてのオブジェクトが返される。Aそのものが返される事もあれば、別のオブジェクトが返される事もある。この流れがメッセージングと呼ばれるものである。返値オブジェクトに対して別のメッセージを送る事も可能であり、また返値オブジェクトをメッセージにして別のオブジェクトに送る事も出来る。こうしたメッセージングの連鎖はAのレシーバー内でも同様に行なわれる。メッセージング・パラダイム下でのオブジェクトは言わば独自の記憶を備えた変換式であり、これらオブジェクトのコミュニケーションとは[[高階関数]]と[[第一級関数]]の仕組みと同じものである。メッセージング・パラダイムの本質はオブジェクトの代数(''algebraizationalgebra'')であり、その代数値は前述のメッセージングの連鎖による結果値である。メッセージングを行なうオブジェクトもまたメッセージング連鎖の集合体という事になる。それはただの[[プリミティブ|プリミティブ値]]であっても決して例外ではない。レシーバーでの処理をコードとすると、メッセージング・パラダイム下でのデータはメッセージング連鎖によるコードの集合体であり、その各コードは他のデータ群を参照しており、その各データもまたコードの集合体~という風になる。勿論最終的には根っことなるオブジェクトの定形データに行き着いてそれが値算出の原点になるが、こうなるとイメージ的にコードとデータが融合して両者の区別なくなる。オブジェクトは抽象化の一形態である代数的(''algebraic'')存在なので、代数計算と同様に理念的には単体で成り立つ事はなく、二つのオブジェクトが出会うメッセージングによって始めて一定のプロセスが発生し、または一つのデータが体現される。これが引数無しでもよいメソッドと引数が要るメッセージングの明確な違いである。
 
なお、実装面では便宜上の理由から、メッセージングの際の引数オブジェクトにはセレクタを付けるのが許容されている。大抵は「A ''selector'':B」の様になる。セレクタはメソッド名と同義であり、引数オブジェクトに貼られるラベルと考えていいものである。セレクタによってレシーバー外の対応メソッドに自動分岐されるのでコーディングが簡便になる。[[演算子]]も事実上のセレクタであり「5+3」は、+セレクタを貼った3オブジェクトを5に送ると解釈できる。括弧記号はコンパイラのためのただの[[ディレクティブ]]となる。メッセージングは二つのオブジェクトが出会った時点で発生するプロセスなので引数は常に一つであり、複数の引数を用いたい場合はパーシャルアプリケーションまたは[[カリー化]]を適用するべきであるが、これは困難なコーディングになる事が多いので、セレクタによる[[パターンマッチング]]的な各メソッドへの自動分岐も許容されている。
62 ⟶ 68行目:
=== 遅延バインディング ===
{{節スタブ}}
 
 
== 歴史 ==