「オブジェクト指向プログラミング」の版間の差分
削除された内容 追加された内容
タグ: Refタグつき記述の除去 |
Goldensundown2 (会話 | 投稿記録) |
||
(同じ利用者による、間の24版が非表示) | |||
1行目:
{{独自研究|date=2018年2月}}
{{プログラミング言語|index=おふしえくとしこうふろくらみんく}}
[[ファイル:History of object-oriented programming languages.svg|サムネイル|OOP言語の系譜(水色がOOP)|代替文=|280x280ピクセル]]
'''オブジェクト指向プログラミング'''(オブジェクトしこうプログラミング
オブジェクト指向プログラミングは、ソフトウェアの大規模化に伴い、より効率的な開発手法が模索される中で1960年代に考案された。OOP言語は歴史的にクラス構造を中心とする''[[Simula]]''系統と、メッセージ機能を主体とする''[[Smalltalk]]''系統に分けられるが、後に''[[C++]]''や''[[Java]]''などの言語が派生した前者が主流となった。この前者のオブジェクト指向が示す「[[カプセル化|内部隠蔽]]」「[[継承 (プログラミング)|継承]]」「[[ポリモーフィズム|多態性]]」の三仕様を備えていれば、OOP言語であると見なされる。
== 特徴 ==▼
*[[ポリモーフィズム]]([[多態性]]、[[多相性]]) ▼
OOP環境の主な仕様は以下の通りである。括弧内の名称はやや意訳したものである。
#[[カプセル化|エンカプセレーション(内部隠蔽)]]
#[[インヘリタンス|インヘリタンス(継承)]]
#*[[多重定義|オーバーローディング(多重定義)]]
#*[[ジェネリックプログラミング|パラメティックポリモーフィズム(型準拠生成)]]
#*[[仮想関数|バーチャルファンクション(仮想関数)]]
#*[[多重ディスパッチ|マルチプルディスパッチ(多択展開)]]
#[[メッセージパッシング|メッセージパッシング(伝言送受)]]
#''etc..''
'''エンカプセレーション'''
== 背景 ==▼
従来のプログラミング環境では、「動作」を定義する'''コード'''が、「状態」を表現する'''データ'''を扱う形でプログラムを記述するのが一般的だったが、開発規模の拡大に伴い、解決の難しいソフトウェア・バグ原因の大半は「データの予期せぬ変動」と「各データ間の予期せぬ不整合」である事が経験則で知られるようになって来た。そこでデータを中心にしてプログラムを組み立てようとする考え方が生まれ、データ群とそれに付随するコード群をまとめた'''オブジェクト'''というプログラミング概念が編み出された。従来の「コードの為のデータ」とは逆に「データの為のコード」としたのは、データを変動させたコード位置を容易に特定出来るようにしてバグ発見に繋げる為であった。この目的に沿って特定のデータを扱えるコード範囲を厳密に定めた'''内部隠蔽'''の仕様は、アクセス許可外のコード記述をエラー警告して、想定外のデータ変動をもたらす人的ミスを減らした。
'''インヘリタンス'''
また、プログラム内の膨大な数のデータは通常グループ化(構造体)されて扱われていたが、各構造体間にまたがる共通のデータ集合が多数出現し、その冗長性と整合の頻雑さの問題が浮き彫りとなっていた。これを解決する為にOOPは、構造体=オブジェクトを複数の'''階層要素'''に分け、共通のデータ集合を親階層とし、派生する子階層に親階層の参照アドレスを持たせて連結する構造とした。A階層から成る親オブジェクトから派生した子オブジェクトはA+B階層として構成され、これが'''継承'''と呼ばれた。コードから参照されたデータがB階層に無い時は、次のA階層に有るか探す仕組みとなり、この連鎖によって傍からは一つのオブジェクトとして存在した。なお、派生クラスで任意のデータとメソッドを追加出来る継承の機能は、同時にコードの再利用性を高めるとも見なされたが、深い継承がもたらす構成把握の難化がネックとなってほぼ否定されるに到った。現在では深い継承は回避される様になり、代わりに共通メソッド呼出テーブル(''Java''のinterfaceなど)を実装させる横に長い継承が主流となっている。また、''simula''系統のOOP言語では多態性を実現する為の重要な手段として用いられている。
'''ポリモーフィズム'''
様々なオブジェクトタイプ(型式)が扱われるソースコード記述の頻雑性を回避する為に、呼出引数に応じたメソッドをコンパイル時に選択する'''多重定義'''と、引数型に合わせたクラスorメソッドをコンパイル時に全生成する'''型準拠生成'''の書式が備えられた。これらはスタティック(静的)な多態性とされる。ダイナミック(動的)な'''多態性'''としては、特定の場面で扱われるオブジェクト群が共通して持つ階層要素の部分で一括りにして順次処理を行い、条件分岐をより柔軟かつ簡素にする目的で、特定の階層のコードの存在を抽象化して呼び出しポイントとし、オブジェクト共通の階層要素が持つ呼び出しポイントから、それぞれ異なる派生先階層の実装コードを呼び出すという'''仮想関数'''の仕組みが実装された。また、オブジェクトが特定の階層要素を持つかチェックした上でその階層に準じた型変化を行い、そのオブジェクトを引数にした多重定義と仮想関数呼び出しの併せ技である'''多択展開'''の機能も編み出され、データがコードを制御するというOOPの理念は明確に表現された。
'''メッセージパッシング'''
上述の三つの仕様と異なり、メッセージパッシングはオブジェクト指向そのものと肩を並べるパラダイムであり、オブジェクト指向が示す機能の大半を結果的に実現出来る「[[メタデータ|メタ]]」的な土台となった。これは従来のサブルーチンコールの形態を変えたもので、基本はバイトデータ('''メッセージ''')の送受信でメソッド名とパラメータ値およびリターン値をやり取りする仕組みだった。オブジェクトのレシーバー関数が引数として渡されたメッセージを読み込み、オブジェクト内部でそれに準じた処理を行い、結果をリターンした。レシーバーの仕組みは結果的に「内部隠蔽」を実現出来た。オブジェクト内部での自由自在な処理実装によるリターンはこれも結果的に「多態性」を実現出来た。メッセージパッシングがもたらす変幻自在なメソッドの選択実行は、通信網を介して他サーバー上で実行されてるサービスプロセスを自身のソフトウェアの一部として扱う様な事も可能にした。あらゆる手法に応用出来るメッセージパッシングは、その適用範囲を広げるほど開発工数と実行負荷も増大するので、決してオールマイティに用いられるものではないが、ソフトウェアのモジュール化およびコンポーネント化をよりダイナミックに、そしてグローバルに発展させる潜在力を秘めており、OOPがもたらす実装の拡張性を大きく広げた。
オブジェクト指向プログラミングという考え方が生まれた背景には、計算機の性能向上によって従来より大規模な[[ソフトウェア]]が書かれるようになってきたということが挙げられる。大規模なソフトウェアが書かれコードも複雑化してゆくにつれ、ソフトウェア開発コストが上昇し、[[1960年代]]には「[[ソフトウェア危機]] ({{Lang|en|software crisis}})」といったようなことも危惧されるようになってきた。そこでソフトウェアの[[再利用 (プログラミング)|再利用]]、[[部品化 (プログラミング)|部品化]]といったようなことを意識した仕組みの開発や、[[ソフトウェア開発工程]]の体系化('''[[ソフトウェア工学]]''' ({{Lang|en|software engineering}}) の誕生)などが行われるようになった。
31 ⟶ 52行目:
[[1980年]]代後半に次々と生まれたオブジェクト指向分析・設計論は、[[Smalltalk]]を源流とするオブジェクト指向を基に組み立てられた。このときSmalltalkは健在であったが広く普及しているとは言えず[[C++]]で[[実装]]する機会が多かったが、C++はSmalltalkとは思想的にやや異なることと、仕様の複雑さが問題とされた。このニーズを受けC++の提示した現実解と、Smalltalk的理想論を融合するものとして、構文面ではシンプル化しながらも強くC++の影響を受けつつ、一方で用語や思想面でSmalltalk色を濃くした{{Citation needed|date=2018年2月}}[[Java]]([[1991年]])が作られた。バランス感覚に長けたJavaの登場によって[[オブジェクト指向開発]]に必要な要素が全てそろい、[[1990年代]]後半からオブジェクト指向は広く普及するようになった。
==
オブジェクト指向プログラミングをサポートする機能を備える代表的な[[プログラミング言語]]([[オブジェクト指向プログラミング言語]])としては以下のようなものが挙げられる:
88 ⟶ 109行目:
: 「純粋」という用語をどう定義するかによるが、たとえば[[Smalltalk]]や[[Ruby]]のように「あらゆる対象がオブジェクトである」という言語(たとえば、Rubyではnilも、ヌルポインタのようなものではなく、NilClassのインスタンスというオブジェクトである。この場合対照例としては、通常の数値型などがオブジェクトでない[[Java]]であろう)を「純粋だ」と言う者もいれば、「当初からオブジェクト指向プログラミング言語として設計された」言語を「純粋だ」と言う者もいる(こちらの定義ではJavaも含まれるだろうか)。例としては、以上のどちらの基準か、それとも別の定義によるものかは知らないが、[[Smalltalk]]、[[Eiffel]]、[[Self]]、[[Ruby]]、[[Swift (プログラミング言語)|Swift]]などを挙げる者がいる。
== OOP言語の仕組み ==
オブジェクト指向プログラミング言語では、オブジェクトへの[[参照 (情報工学)|参照]]や[[ポインタ (プログラミング)|ポインタ]]が多用される。そのため、オブジェクトの[[メモリ]]への割り当てに関して、自動[[ガベージコレクション]]機能を備えているものが多い。ただし、すべての言語が備えているわけではない。例えば、C++はガベージコレクションを備えていない。▼
オブジェクト指向プログラミング言語は、相互に'''[[#メッセージ|メッセージ]]'''を送りあう'''[[オブジェクト (プログラミング)|オブジェクト]]'''の集まりとして[[プログラム (コンピュータ)|プログラム]]を構成することができる仕組みを持つ。
そのために、少なくともオブジェクトについての3つの仕組みと、オブジェクトの管理についての3つの仕組みが必要となる。
;オブジェクトの仕組み
:* オブジェクトに蓄えられる情報、データを表現する仕組み。
120 ⟶ 133行目:
* 概念的には コードとデータが一つになっている。
==== オブジェクト
実際のプログラムでは、全てのオブジェクトが互いに全く異なった存在ではなくオブジェクトは種類に分けることが出来る。
127 ⟶ 140行目:
このような場合、各オブジェクトがそれぞれメッセージ処理のコード(前述の「振る舞い」に当たる)を独自に備えていては無駄である。そこでオブジェクト指向プログラミング言語がオブジェクトを実現する際には多くの場合、内部的にはオブジェクトを2つの部分に分けている。
一つは同一種類のオブジェクトに共有される部分、例えばメッセージ処理のコード(振る舞い)や定数(どのオブジェクトでも異ならないデータ)の類である。
もう一つは同一種類のオブジェクトでもそれぞれ異なる部分、典型的には各オブジェクトが保持するデータ群である。
==== インスタンスオブジェクトとクラスオブジェクト ====▼
==== メッセージの処理のされ方 ====▼
動的型付けを採用するオブジェクト指向言語の多くは、クラスより生成するインスタンスの他に[[メタクラス]]という機能を持ちクラス自体をオブジェクトとして扱うことが出来る。このためオブジェクトには、インスタンスオブジェクトとクラスオブジェクトという2種類のオブジェクトが存在する。Java等クラスオブジェクトを持たない言語の文化圏では、インスタンスオブジェクトとオブジェクトを混同して説明される事があるが、Objective-CやPython、Ruby等、インスタンスオブジェクトとクラスオブジェクトが別であるオブジェクト指向言語では区別して説明される。<ref>Objective-Cプログラミ▼
ング言語[https://developer.apple.com/jp/devcenter/ios/library/documentation/ObjC.pdf]</ref>▼
<ref>Classes ― Python v2.7.3 documentation[http://docs.python.org/2/tutorial/classes.html]</ref>▼
<ref>クラス/メソッドの定義 (Ruby manual) [http://www.ruby-lang.org/ja/old-man/html/_A5AFA5E9A5B9A1BFA5E1A5BDA5C3A5C9A4CEC4EAB5C1.html]</ref>元々はSmalltalkから始まった用語である。▼
{{seealso|this (プログラミング)}}
そしてあるオブジェクトOにメッセージを配送し適切なメッセージ処理コード(振る舞い)を呼び出す際には、まず対象となるオブジェクトOについて共通部分の格納場所を見つけて適切なコードを選び出し、次にそのコードに対して処理対象となるオブジェクトO固有のデータの所在を示す'''オブジェクトID'''を渡すようになっている。
141 ⟶ 162行目:
また各オブジェクトの固有データから共通部分の格納場所を見つける方法もまた各言語により異なり、その言語の開発目的に応じて実に多種多様である。
例えば[[JavaScript]]の場合、各オブジェクトは[[連想配列]]であり、名前で表現されたメッセージのIDからメッセージ処理コードである関数への参照を直接見つけ出す。各オブジェクトの固有データもその連想配列に格納されていて、メッセージを処理する関数には連想配列のアドレスが渡される。
[[Self]]のような[[プロトタイプベース|インスタンスベース]]のオブジェクト指向プログラミング言語では、プロトタイプとなるオブジェクトがメッセージを処理するコードも保持しており、オブジェクトがクローンされて作成されるときにそのプロトタイプのありかを示す情報もコピーされ、メッセージは受け取ったオブジェクトのIDを添えてプロトタイプに送られて処理される(Selfでは実行効率上の問題から後に内部的にクラスを作って利用するようになっている)。
最も普及している[[クラスベース]]の言語では、共通部分はオブジェクトの種類を表現するクラスに保持され、各オブジェクトは固有データと共にそのクラスのIDを保持する。そしてオブジェクトに送られるメッセージはその送り先オブジェクトにあるクラスのIDからクラスを見つけ、その中からメッセージを処理するコードを見つけ出し、処理対象となっているオブジェクトのIDを付してそのコードを呼び出す仕組みになっている。
168 ⟶ 192行目:
=== クラス ===
{{main|クラス (コンピュータ)}}
==== クラスベース ====
'''クラス''' (class) は大多数のオブジェクト指向プログラミング言語で提供されている仕組みであり、上記の機能の殆ど全てに関わりがある。概念的にはクラスはオブジェクトの種類を表す。このためオブジェクトはクラスに'''属する'''という言い方をする。あるクラスに属するオブジェクトのことをそのクラスの'''インスタンス''' (instance) と呼ぶ。[[データ型]]の理論から見た場合クラスは型を定義する手段の一つである。クラスによってオブジェクトを記述する言語を'''[[クラスベース]]''' ({{Lang|en|class-based}}) のオブジェクト指向プログラミング言語と呼ぶ。
180 ⟶ 205行目:
クラスは非常に多くのオブジェクト指向プログラミング言語で提供されている機能ではあるが、オブジェクト指向プログラミング言語に必須の機能というわけではない。実際にオブジェクトの管理や、データ・メンバや[[メソッド (計算機科学)|メソッド]]の記述、[[継承 (プログラミング)|継承]]に際してクラスという仕組みに依存せずに、もしくはクラスという仕組み自体を持たずに別の手段でこれらを実現している言語も存在する。このような言語を'''[[プロトタイプベース|インスタンスベース]]''' (''{{Lang|en|instance-based}}'')、'''オブジェクトベース''' (''object-based'') あるいは'''プロトタイプベース''' (''{{Lang|en|prototype-based}}'') のオブジェクト指向プログラミング言語と呼ぶ。インスタンスベースまたはそれに類するのオブジェクト指向プログラミング言語には以下のようなものがある:
*
*
*
*
* Squeak [[Etoys|eToys]]([[Squeak]]の非開発者向けビジュアルスクリプト言語。SqueakToys とも)
210 ⟶ 235行目:
ただし、Smalltalkのクラス変数はC++やJavaのクラス変数とは異なる。Smalltalkにおいて、C++やJavaのクラス変数と同等となる変数は'''プール辞書''' ({{Lang|en|pool dictionary}}) と呼ばれる。
▲=== インスタンスオブジェクトとクラスオブジェクト ===
▲動的型付けを採用するオブジェクト指向言語の多くは、クラスより生成するインスタンスの他に[[メタクラス]]という機能を持ちクラス自体をオブジェクトとして扱うことが出来る。このためオブジェクトには、インスタンスオブジェクトとクラスオブジェクトという2種類のオブジェクトが存在する。Java等クラスオブジェクトを持たない言語の文化圏では、インスタンスオブジェクトとオブジェクトを混同して説明される事があるが、Objective-CやPython、Ruby等、インスタンスオブジェクトとクラスオブジェクトが別であるオブジェクト指向言語では区別して説明される。<ref>Objective-Cプログラミ
▲ング言語[https://developer.apple.com/jp/devcenter/ios/library/documentation/ObjC.pdf]</ref>
▲<ref>Classes ― Python v2.7.3 documentation[http://docs.python.org/2/tutorial/classes.html]</ref>
▲<ref>クラス/メソッドの定義 (Ruby manual) [http://www.ruby-lang.org/ja/old-man/html/_A5AFA5E9A5B9A1BFA5E1A5BDA5C3A5C9A4CEC4EAB5C1.html]</ref>元々はSmalltalkから始まった用語である。
=== メソッド ===
223 ⟶ 242行目:
[[C++]]ではメソッドは'''メンバ関数''' ({{Lang|en|member function}}) や'''関数メンバ''' (function member) と呼ばれる。これはC++が[[グローバル関数]]との区別をつけることと、クラスを[[抽象データ型]]の拡張と位置づけ、非メッセージメタファな言語思想を持っている為である。これら言語ではメソッドをオブジェクト(=クラスやインスタンス)の持ち物として捉えず、クラスに定義された機能要素であると考える。メッセージメタファを否定するため、同時にメッセージを実行するメソッド(手法)ではありえない。
==== クラスメソッド
[[メソッド (計算機科学)#静的メソッド|クラス・メソッド]]だが、オブジェクト指向の本義に立ち返れば、クラス・メソッドがあるということはクラスがメッセージをレシーブできるという事になる。
234 ⟶ 253行目:
[[Smalltalk]]ではクラスもオブジェクトの一種であるため当然クラスはメソッドをもつ。
クラス・メソッドは、C++では'''静的メンバ関数''' ({{Lang|en|static member function}}) と呼ばれる。これはクラスがオブジェクトでない言語にとってはクラス・メソッドより正確な表現であり適切である。("static" とはCの'''static変数'''に由来し'''auto変数'''の対語である。関数コールによりスタック上に生成される関数インスタンスに依存しない変数と、インスタンス生成有無にかかわらず実行できる関数の類似による。)
Javaではクラス・メソッドは'''静的メソッド''' ({{Lang|en|static method}}) とも呼ばれることもある。
==== システムメソッド ====
言語によっては特定の名前のインスタンス・メソッドやクラス・メソッドにオブジェクトの生成、初期化、複製、廃棄といった機能を固定的に割り当てている。
==== コンストラクタとデストラクタ ====
初期化に利用されるメソッドを'''[[コンストラクタ]]'''あるいは'''構築子''' ({{Lang|en|constructor}})、廃棄時に利用されるメソッドを'''[[デストラクタ]]'''あるいは'''消滅子''' ({{Lang|en|destructor}}) と呼んで特別に扱うことが多い。
252 ⟶ 272行目:
C++とJavaの場合、各クラスの名前がコンストラクタの名前として使用される。C++では一部のコンストラクタは[[型変換演算子]]として、また[[暗黙の型変換]]にも利用される。
=== ガーベジコレクション ===
▲オブジェクト指向プログラミング言語では、オブジェクトへの[[参照 (情報工学)|参照]]や[[ポインタ (プログラミング)|ポインタ]]が多用される。そのため、オブジェクトの[[メモリ]]への割り当てに関して、自動[[ガベージコレクション]]機能を備えているものが多い。ただし、すべての言語が備えているわけではない。例えば、C++はガベージコレクションを備えていない。
=== アクセス権 ===
|