「オブジェクト指向プログラミング」の版間の差分
用語と解説 |
デザインパターン一覧 タグ: ビジュアルエディター: 中途切替 曖昧さ回避ページへのリンク |
||
(15人の利用者による、間の136版が非表示) | |||
3行目: | 3行目: | ||
|出典の明記=2019年2月 |
|出典の明記=2019年2月 |
||
}} |
}} |
||
[[ファイル:Object oriented design object.jpg|境界|右|フレームなし]] |
|||
{{プログラミング・パラダイム}} |
{{プログラミング・パラダイム}} |
||
{{Wikibooks|オブジェクト指向|オブジェクト指向}} |
|||
'''オブジェクト指向プログラミング'''(オブジェクトしこうプログラミング、{{Lang-en-short|''object-oriented programming''}}、略語:OOP)とは「[[オブジェクト (プログラミング)|オブジェクト]]」という概念に基づいた[[プログラミングパラダイム]]の一つである。 |
|||
オブジェクトは、任意個数の[[フィールド (計算機科学)|フィールド ]]([[属性]]、[[プロパティ]]または[[変数 (プログラミング)|変数]])で構成される'''[[データ]]'''と、任意個数の([[メソッド (計算機科学)|メソッド]]または[[関数 (プログラミング)|関数]])で構成される'''[[コード]]'''のひとまとまりで構成される。 |
|||
オブジェクトの特徴として、オブジェクト自身の手続きが自身のデータフィールドを読み書きできることが挙げられる(オブジェクトには[[this (プログラミング)|{{code|this|C++}}]]や{{code|self}}という概念がある)。また、OOPでは、相互に作用するオブジェクトを組み合わせてプログラムを設計する<ref>{{Cite journal |
|||
| last1 = Kindler | first1 = E. |
|||
| last2 = Krivy | first2 = I. |
|||
| title = Object-Oriented Simulation of systems with sophisticated control |
|||
| publisher = International Journal of General Systems |
|||
| year = 2011 | pages = 313–343}}</ref><ref>{{Cite book|last1=Lewis|first1=John|last2=Loftus|first2= William|title=Java Software Solutions Foundations of Programming Design 6th ed|publisher=Pearson Education Inc.|year=2008|isbn=978-0-321-53205-3}}, section 1.6 "Object-Oriented Programming"</ref>。OOP言語のありかたは多様であるが、最も一般的といえるものは、オブジェクトがクラスの[[インスタンス]]であり、また、オブジェクトの[[データ型|型]]も[[クラス (コンピュータ)|クラス]]として規定される[[クラスベース]]といわれるものである。 |
|||
広く使われているプログラミング言語の多く(C++、Java、Pythonなど)は、[[マルチパラダイムプログラミング言語|マルチパラダイム]]であるが、程度の差はあれ、オブジェクト指向プログラミングをサポートしており、大抵は[[命令型プログラミング|命令型]]や[[手続き型プログラミング]]との組み合わせで用いられる。 |
|||
主なオブジェクト指向言語には次のようなものが挙げられる: |
|||
[[Java]]、[[C++]]、[[C_Sharp|C#]]、[[Python]]、[[R言語|R]]、[[PHP (プログラミング言語)|PHP]]、[[Visual_Basic_.NET]]、[[JavaScript]]、[[Ruby]]、[[Perl]]、[[:en:SIMSCRIPT|SIMSCRIPT(英語版)]]、[[Object Pascal]]、[[Objective-C]]、[[Dart]]、[[Swift (プログラミング言語)|Swift]]、[[Scala]]、[[Kotlin]]、[[Common Lisp]]、[[MATLAB]]、そして[[Smalltalk]]。 |
|||
<!-- 以上まで、ほぼ [[en:Object-oriented programming]] oldid=1047374345 の翻訳 --><!-- 以下より文末までほぼ出典なしの記述(出典なしの記述が大量に続いている、ということが以前より懸念されています。詳細は議論ノートをご参照ください --> |
|||
== 歴史 == |
|||
<!-- 以下、[[en:Object-oriented programming]] oldid=1047374345 の翻訳 --> |
|||
[[File:oop-uml-class-example.png|frame|right|[[統一モデリング言語|UML]]によるクラスの表記法。このButtonクラスは、データを表す[[変数 (プログラミング)|変数]]と[[メソッド (計算機科学)|関数]]を持ち、継承によりButtonクラスのサブセットとしてサブクラスを作成することが可能である。また、オブジェクトはクラスのインスタンスである。]] |
|||
現在のオブジェクト指向プログラミングという文脈における「オブジェクト」や「指向」を表す用語が初めて登場したのは、1950年代後半から1960年代前半にかけての[[マサチューセッツ工科大学|マサチューセッツ工科大学(MIT)]]においてである。 |
|||
1960年代初頭の[[人工知能]]グループ界隈では、「オブジェクト」はプロパティ(属性)を持つ個体識別可能なアイテム([[LISP]]のatom)を意味していた<ref>{{Cite journal |
|||
|last1=McCarthy |
|||
|first1=J. |
|||
|last2=Brayton |
|||
|first2=R. |
|||
|author2-link=:en:Robert Brayton (computer scientist) |
|||
|last3=Edwards |
|||
|first3=D. |
|||
|author3-link=:en:Daniel Edwards (programmer) |
|||
|last4=Fox |
|||
|first4=P. |
|||
|author4-link=:en:Phyllis Fox |
|||
|last5=Hodes |
|||
|first5=L. |
|||
|author5-link=:en:Louis Hodes |
|||
|last6=Luckham |
|||
|first6=D. |
|||
|author6-link=:en:David Luckham |
|||
|last7=Maling |
|||
|first7=K. |
|||
|author7-link=:en:Klim Maling (programmer) |
|||
|last8=Park |
|||
|first8=D. |
|||
|author8-link=:en:David Park (computer scientist) |
|||
|last9=Russell |
|||
|first9=S. |
|||
|author9-link=:en:Steve Russell (computer scientist) |
|||
|title=LISP I Programmers Manual |
|||
|place=[[:en:Boston]], [[:en:Massachusetts]] |
|||
|publisher=Artificial Intelligence Group, [[:en:M.I.T. Computation Center]] and Research Laboratory |
|||
|date=March 1960 |
|||
|page=88f |
|||
|url=http://history.siam.org/sup/Fox_1960_LISP.pdf |
|||
|quote=In the local M.I.T. patois, association lists [of atomic symbols] are also referred to as "property lists", and atomic symbols are sometimes called "objects". |
|||
|url-status=dead |
|||
|archive-date=17 July 2010 |
|||
|archiveurl=https://web.archive.org/web/20100717111134/http://history.siam.org/sup/Fox_1960_LISP.pdf |
|||
}}</ref><ref>{{Cite book |
|||
|url = https://archive.org/details/lisp15programmer00john/page/105 |
|||
|title = LISP 1.5 Programmer's Manual |
|||
|publisher = [[:en:MIT Press]] |
|||
|first1 = John |
|||
|last1 = McCarthy |
|||
|author-link = :en:John McCarthy (computer scientist) |
|||
|first2 = Paul W. |
|||
|last2 = Abrahams |
|||
|first3 = Daniel J. |
|||
|last3 = Edwards |
|||
|author3-link = :en:Daniel Edwards (programmer) |
|||
|first4 = swapnil d. |
|||
|last4 = Hart |
|||
|first5 = Michael I. |
|||
|last5 = Levin |
|||
|isbn = 978-0-262-13011-0 |
|||
|year = 1962 |
|||
|page = [https://archive.org/details/lisp15programmer00john/page/105 105] |
|||
|quote = Object — a synonym for atomic symbol |
|||
|df = dmy-all |
|||
}}</ref>。 |
|||
後に[[アラン・ケイ]]は、1966年にLISPの内部構造を詳細に理解したことが彼の考え方に強い影響を与えたと述べている。<ref name=alanKayOnOO>{{Cite web|url= http://www.purl.org/stefan_ram/pub/doc_kay_oop_en |title=Dr. Alan Kay on the Meaning of "Object-Oriented Programming" |year= 2003|access-date=11 February 2010}}</ref> |
|||
{{Quote box |
|||
|quote = 私は、オブジェクトとは、生物の細胞やネットワーク上の個々のコンピュータのようもの、そしてそれらのコミュニケーションは専らメッセージによって行なわれるもの、と考えていました(つまり、メッセージングは最初から存在していたのですが、プログラミング言語でメッセージングを実用的かつ効率的に行う方法を見つけるまでには時間がかかりました)。 |
|||
|author = アラン・ケイ |
|||
|source =<ref name=alanKayOnOO /> |
|||
|width = 50% |
|||
}} |
|||
MITにおける初期の例としては、この他にも、1960年から1961年にかけて[[アイバン・サザランド]]が作成した[[Sketchpad]]が挙げられる。サザランドは、1963年の技術レポートの用語集(Sketchpadに関する自身の博士論文をもとにしたもの)で、グラフィカルなインタラクションに特化しているとはいえ「オブジェクト」と「インスタンス」の概念を定義している(クラスの概念は"master"または"definition"として把握されている)。<ref>{{Cite web|url=http://handle.dtic.mil/100.2/AD404549|title=Sketchpad: A Man-Machine Graphical Communication System|author=Sutherland, I. E.|date=30 January 1963|publisher=Technical Report No. 296, Lincoln Laboratory, Massachusetts Institute of Technology via Defense Technical Information Center (stinet.dtic.mil)|access-date=17 July 2019}}<!-- Seems to be fixed {{dead link|date=February 2018 |bot=InternetArchiveBot |fix-attempted=yes }} --> |
|||
</ref> |
|||
また、MIT版の[[ALGOL]]であるAED-0では、データ構造(この言語の方言では"plexes"と呼称)と手続きを直接結びつけ、後に「メッセージ」、「メソッド」、「メンバ関数」と呼ばれるようなものの萌芽がみられる。<ref name=simuladev> |
|||
The Development of the Simula Languages, |
|||
[[:en:Kristen Nygaard]], [[:en:Ole-Johan Dahl]], |
|||
p.254 |
|||
[http://cs-exhibitions.uni-klu.ac.at/fileadmin/template/documents/text/The_development_of_the_simula_languages.pdf Uni-kl.ac.at] |
|||
</ref><ref> |
|||
{{Cite web |
|||
|last = Ross |first = Doug |
|||
|title = The first software engineering language |
|||
|work = LCS/AI Lab Timeline |
|||
|publisher = MIT Computer Science and Artificial Intelligence Laboratory |
|||
|url = http://www.csail.mit.edu/timeline/timeline.php?query=event&id=19 |
|||
|access-date =13 May 2010 }} |
|||
</ref> |
|||
<!-- 以上、[[en:Object-oriented programming]] oldid=1047374345 の翻訳 --> |
|||
<!-- 以下、[[en:Object-oriented programming]] oldid=1047374345 の翻訳 --> |
|||
1962年、[[クリステン・ニゴール]]は[[:en:Norwegian Computing Center|ノルウェー計算センター]]でシミュレーション言語のプロジェクトを開始した。これは彼が以前に用いた[[モンテカルロ法]]と実世界のシステムを概念化する仕事に基づくものであった。[[オーレ=ヨハン・ダール]]が正式にプロジェクトに参加し、[[UNIVAC I]](UNIVAC 1107)上で動作する[[Simula]]プログラミング言語が設計された。Simulaは、[[クラス (コンピュータ)|クラス]]や[[オブジェクト (プログラミング)|オブジェクト]]、継承、[[ダイナミックバインディング]]など、今日のオブジェクト指向プログラミングには不可欠である重要な概念を導入した。<ref name="auto">{{Cite journal|last = Holmevik|first = Jan Rune|title = Compiling Simula: A historical study of technological genesis|journal = IEEE Annals of the History of Computing|volume = 16|issue = 4|pages = 25–37|year = 1994|url = http://www.idi.ntnu.no/grupper/su/publ/simula/holmevik-simula-ieeeannals94.pdf|doi = 10.1109/85.329756|s2cid = 18148999|access-date = 3 March 2018|archive-date = 30 August 2017|archiveurl = https://web.archive.org/web/20170830065454/http://www.idi.ntnu.no/grupper/su/publ/simula/holmevik-simula-ieeeannals94.pdf|url-status = dead}}</ref> |
|||
Simulaはまた、プログラミングにおける[[:en:Data security|データ保全]]を考慮して設計されたものでもあった。プログラミングのデータ保全のために[[参照カウント]]による検出プロセスが実装されたのに加え、最終手段として[[ガベージコレクション|ガベージコレクタ]]が[[Random Access Memory|メモリ]]内の使用されていないオブジェクトを削除するようになっていた。しかし、データオブジェクトの概念は1965年には既に確立されていたものの、プライベート(-)やパブリック(+)といった[[変数 (プログラミング)|変数]]の[[スコープ|スコープのレベル]]によるデータのカプセル化については、アクセスする手続きもまた隠蔽できなければならなかったため、Simulaでは実装されなかった。<ref>{{Cite book|last = Dahl |first = Ole Johan|year = 2004 |chapter-url = http://www.mn.uio.no/ifi/english/about/ole-johan-dahl/bibliography/the-birth-of-object-orientation-the-simula-languages.pdf |doi = 10.1007/978-3-540-39993-3_3|access-date =3 March 2018 |chapter = The Birth of Object Orientation: The Simula Languages|title = From Object-Orientation to Formal Methods|volume = 2635|pages = 15–25|series = Lecture Notes in Computer Science|isbn = 978-3-540-21366-6|citeseerx = 10.1.1.133.6730}|access-date = 21 October 2021}</ref> |
|||
<!-- 以上、[[en:Object-oriented programming]] oldid=1047374345 の翻訳 --> |
|||
<!-- 以下、[[en:Object-oriented programming]] oldid=1047374345 の翻訳 --> |
|||
初期の段階では、Simulaはプログラミング言語[[ALGOL]] 60のための手続きパッケージとされていた。しかし、ALGOLによる制約に不満を感じた研究者たちは、UNIVAC ALGOL 60コンパイラを使用した本格的なプログラミング言語としてSimulaを開発することにした。ダールとニゴールは1965年から1966年にかけてSimulaの普及に尽力し、スウェーデン、ドイツ、[[ソビエト連邦]]などでSimulaの使用が増加した。1968年には、[[バロース B5000]]上で広く利用されるようになり、後には[[:en:Ural (computer)|URAL-16コンピュータ]]上にも実装された。1966年、ダールとニゴールはSimulaの[[コンパイラ]]を書いた。彼らは、{{仮リンク|SIMSCRIPT|en|SIMSCRIPT}}(自由形式の英語的な汎用シミュレーション言語)を実装に用いて、[[アントニー・ホーア]]のレコード・クラス概念を取り入れることに熱心に取り組んだが、彼らは、一般化されたプロセスの概念として、レコード・クラスの属性を保持する層と、接頭辞(prefix)の系列を保持する層の二層構造とする方式に辿り着いた。 |
|||
接頭辞の系列を通じて、プロセスは先行する定義を参照し、それらの属性を追加することができる。このようにしてSimulaは、クラスとサブクラスの階層を導入し、これらのクラスからオブジェクトを生成することを可能にする方法を導入することとなった。<ref>{{ |
|||
Cite journal| |
|||
last = Nygaard| |
|||
first = Kristen| |
|||
title = The Development of the SIMULA Languages| |
|||
journal = ACM SIGPLAN Notices| |
|||
volume = 13| |
|||
issue = 8| |
|||
pages = 245–272| |
|||
year = 1978| |
|||
url = https://doi.org/10.1145/960118.808391| |
|||
doi = 10.1145/960118.808391| |
|||
access-date = 22 October 2021| |
|||
}} |
|||
</ref> |
|||
<!-- 以上、[[en:Object-oriented programming]] oldid=1047374345 の翻訳 --> |
|||
<!-- 以下、[[en:Object-oriented programming]] oldid=1051149906 の翻訳 --> |
|||
1972年には[[System/360|IBM System/360]]および[[System/370|IBM System/370]]の[[IBMメインフレーム]]用にSimula 67コンパイラが完成<ref name="auto"/>。同年、フランスの[[CII 10070]]および[[CII Iris]] 80[[メインフレーム]]用のSimula 67コンパイラが無償で提供された。1974年には、Simulaユーザー会は23カ国のメンバーを有するまでになっていた。1975年初頭、[[PDP-10|DECsystem-10]]メインフレームファミリー用のSimula 67コンパイラが無償でリリースされ、同年8月までにDECsystem-10のSimula 67コンパイラは28サイトにインストールされた(そのうちの22サイトは北米)。オブジェクト指向のプログラミング言語としてSimulaは、貨物港における船舶と積載貨物の動きを調査・改善するための研究のような、[[物理モデル音源|物理モデリング]]研究に携わる研究者に主に利用されていた<ref name="auto"/>。 |
|||
<!-- 以上、[[en:Object-oriented programming]] oldid=1051149906 の翻訳 --> |
|||
{{独自研究|date=2021-10}} |
|||
1974年に[[MIT]]の計算機科学者[[バーバラ・リスコフ]]は「[[抽象データ型]]」という概念を提唱し、上述のモジュールの共同詳細化をその振る舞いによって[[セマンティクス|意味内容]]が決定される抽象データという考え方でより明解に形式化した。1975年に計算機科学者[[ニクラウス・ヴィルト]]は、モジュール機能を主題にした言語[[Modula-2|Modula]]と共に{{仮リンク|モジュラルプログラミング|en|Modular programming}}を提唱した。このパラダイムでは、[[モジュール]]を仕様定義とコード/データ実装に分離しての、前者による抽象化と後者の情報隠蔽が備えられて、これは[[インタフェース (抽象型)|インターフェース]]の実装という概念の先例になっている。また、1970年代後半から[[IBM]]社を中心にした研究者たちが([[エドワード・ヨードン]]など)[[サブルーチン]]モジュールと[[データ構造]]を連携させる[[構造化分析設計技法|構造化]]のパラダイムを発表し、こちらではモジュールの抽象指向は倦厭されて具象的な[[段階的詳細化法|段階的詳細化]]が重んじられた。当時は具象指向の方に軍配が上がり、[[構造化プログラミング|構造化開発]]は1980年代までのソフトウェア開発の主流になっている。このようにいささか奇妙ではあるが、Simulaのクラスとオブジェクトというプログラム概念は、[[モジュール|プログラムモジュール]]の登場からモジュラルや[[構造化分析設計技法|構造化開発]]へといった進化の流れとは関係なく、しかもその前段階において生まれていた。 |
|||
Simula発のProcessとクラスの示した可能性は、[[パロアルト研究所]]の計算機科学者[[アラン・ケイ]]による「メッセージング」という考え方のヒントになった。ケイはプログラム内のあらゆる要素をオブジェクトとして扱い、オブジェクトはメッセージの送受信でコミュニケーションするという独特のプログラム理論を提唱した。それには従来の関数呼び出しをセレクタの実行時解釈に置き換えて積極的な[[委譲]]を推進するメッセージ式と、プログラムコードとしても解釈できるデータ列を送信してそれを任意のタイミングで評価(eval)することで新たなデータを導出できるなどのアイディアが盛り込まれていた。これらの遅延結合パラダイムは非同期通信や単方向通信への可能性をも開いており、この発想の背景には[[LISP]]の影響があった。メッセージを駆使するオブジェクトの構築には、Simula発のそれに[[プラトン]]の[[イデア論]]を重ね合わせた[[クラス (コンピュータ)|クラス]]と[[インスタンス]]の仕組みが導入された。オブジェクトとメッセージングの構想に基づいて開発された「[[Smalltalk]]」はプログラミング言語と[[GUI]]フレームワークを併せたものとなり、1972年に[[データゼネラルNova]]上での1000行程度のBASICを使った試作(概念実証)を経て、翌1973年に新開発された[[Alto|ゼロックスAlto]]上で本格稼働された。Smalltalkの設計を説明するためにケイが考案した「[[オブジェクト指向]]」という用語はここで初めて発信された。またケイのメッセージング構想は[[MIT]]の計算機科学者[[カール・ヒューイット]]に能動的な[[プロセス代数]]を意識させて<ref name="アクター">“Our research has concentrated on the development of a rigorous model of computation based on relationship among computational events. The development of this model has been greatly influenced by Seymour Papert's “little people” model of computation, a seminar given by Alan Key at M.I.T. on an early version of Smalltalk, and the work of Church, Fischer, Landin, on formalisms based on the lambda calculus.”[https://dl.acm.org/doi/abs/10.1145/512927.512942|Actor Induction and Meta-evaluation]</ref>、1973年発表の[[アクターモデル]]のヒントにもなっている。しかし委譲の多用とデータ列が常にコード候補としても扱われる処理系は、当時のコンピュータには負荷が大きく実用的な速度を得られないという問題にすぐ直面した。Smalltalk-74(新たに開発された[[BitBLT]]を使った高速描画版Smalltalk-72)からSmalltalk-76の過程で、やむなくメッセージは(多くの場合)関数の動的コールに、メソッドはパターンマッチ処理から単なる関数へ置き換えられるなど構想時の柔軟さが失われるほど最適化された。また、ケイの留保した継承機構<ref name="継承">“I didn't like the way Simula I or Simula 67 did inheritance (though I thought Nygaard and Dahl were just tremendous thinkers and designers). So I decided to leave out inheritance as a built-in feature until I understood it better. ”[http://www.purl.org/stefan_ram/pub/doc_kay_oop_en|Dr. Alan Kay on the Meaning of “Object-Oriented Programming”]</ref>も導入されてオブジェクトは抽象データ型の性格も有するようになった。 |
|||
上述のように'''[[オブジェクト指向]]'''という言葉自体は、計算機科学者[[アラン・ケイ]]によって作り出されている。[[Simula]]言語などにインスパイアされたケイが1967年頃に口にしたと伝えられるこの造語は<ref name="造語">“At Utah sometime after Nov 66 when, influenced by Sketchpad, Simula, the design for the ARPAnet, the Burroughs B5000, and my background in Biology and Mathematics, I thought of an architecture for programming. It was probably in 1967 when someone asked me what I was doing, and I said: "It's object-oriented programming".”[http://www.purl.org/stefan_ram/pub/doc_kay_oop_en%7CDr. Alan Kay on the Meaning of “Object-Oriented Programming”]</ref>、彼が1972年から開発を始めた言語[[Smalltalk]]の設計を説明する過程で明確な用語として発信され、1981年頃から知名度を得るようになった。80年代半ばになるとオブジェクト指向の解釈は、元々のアラン・ケイによる[[Smalltalk]]の様式と、1983年に計算機科学者[[ビャーネ・ストロヴストルップ]]が公開した[[C++]]の様式に二分された。前者では[[メッセージング]]という概念が基礎にされ、後者では[[Simula|Simula67]]由来の諸機能を加えた[[抽象データ型]]のスーパーセットが基礎にされていた。 |
|||
1980年のSmalltalk-80は、元々はメッセージを重視していたケイを自嘲させるほど同期的で双方向的で手続き的なオブジェクト指向へと変貌していた。それでも動的ディスパッチと[[委譲]]でオブジェクトを連携させるスタイルは画期的であり、1994年に発表される[[デザインパターン (ソフトウェア)|デザインパターン]]の模範にもされている。1981年に当時の著名なマイコン専門誌『[[Byte (magazine)|BYTE]]』が、Smalltalkとその理念であるオブジェクト指向を紹介して世間の注目を集める契機になったが、ケイの思惑に反して技術的関心を集めたのはクラスの仕組みの方であった。オブジェクト指向は知名度を得るのと同時に、Simula発の[[クラス (コンピュータ)|クラス]]([[継承 (プログラミング)|継承]]と動的ディスパッチ)および[[抽象データ型]](データ抽象とデータ隠蔽)にマウントされて解釈されるようになり、それらのコンセプトがケイの構想とは無関係であったことから、オブジェクト指向の定義はケイの手を離れて独り歩きするようになった。 |
|||
[[Simula]]を研究対象にしていた[[ベル研究所|AT&Tベル研究所]]の計算機科学者[[ビャーネ・ストロヴストルップ]]は、1979年からクラス付きC言語の制作に取り組み、1983年に「[[C++]]」を公開した。C++で実装された[[クラス (コンピュータ)|クラス]]は、Simula由来の[[継承 (プログラミング)|継承]]と仮想関数に加えて、段階的な[[レキシカルスコープ]]の概念をクラス構造に応用した[[アクセスコントロール]]を備えていた。C++で確立されたアクセスコントロールは情報隠蔽によるデータ抽象を提示したが、コードスタイル上ほとんどザル化されており、その理由からストロヴストルップ自身もC++は正しくない(''not just'')オブジェクト指向言語であると明言している。1986年にソフトウェア技術者[[バートランド・メイヤー]]が制作した「[[Eiffel]]」の方は、正しいオブジェクト指向を標榜してクラスのデータ抽象を遵守させるコードスタイルが導入されていた。クラスメンバ(フィーチャー)は属性/手続き/関数の三種構成で、手続きで属性を変更して関数で属性を閲覧するという形式に限定されており、これは[[抽象データ型]]に忠実な実装であった。アクセスコントロールはC++のとは異なるクラス指名方式にされ、仮想関数機能は延期手続き/関数として実装された。 |
|||
1986年から[[Association for Computing Machinery|ACM]]が[[OOPSLA]]を年度開催するようになり、オブジェクト指向は従来の[[構造化プログラミング|構造化開発]]に代わる技術として明確に意識され始めた。OOPSLAのプログラミング言語セクションでは、[[抽象データ型]]を基礎にした[[クラス (コンピュータ)|クラス]]・パラダイムが主要テーマにされ、それを標準化するための数々のトピックが議題に上げられている。[[モジュール|モジュール分割]]、[[抽象化 (計算機科学)|抽象化]]、[[再利用|再利用性]]、[[継承 (プログラミング)|階層構造]]、複合構成、情報隠蔽、実行時多態、[[動的束縛]]、[[総称型]]、[[永続性]]、[[並行性]]、[[ガベージコレクション|自動メモリ管理]]といったものがそうであり、参画した識者たちによる寄稿、出版、講演を通して世間にも広められた。そうした潮流の中で[[ビャーネ・ストロヴストルップ|ストロヴストルップ]]はデータ抽象の重要性を訴え、[[バーバラ・リスコフ|リスコフ]]は[[上位概念、下位概念、同位概念および同一概念|基底と派生]]に分けたデータ抽象の階層構造の連結関係([[リスコフの置換原則|置換原則]])について提言した。[[契約による設計]]と[[開放/閉鎖原則|開放閉鎖原則]]を提唱する[[バートランド・メイヤー|メイヤー]]が1988年に刊行した『オブジェクト指向ソフトウェア構築』によるEiffel式のクラス理論は高く評価され、Eiffelを現行の模範形とする声も多く上がった。ただしこれは学術寄りの意見でもあったようで、世間のプログラマの間では厳格なEiffelよりも、柔軟で融通の利くC++の人気の方が高まっていた。他方で[[アラン・ケイ]]のメッセージ・メタファに忠実であろうとする動きもあり、1984年に制作された「[[Objective-C]]」はC言語をSmalltalk方向に拡張してメッセージ式を平易化した言語であった。1987年に[[パロアルト研究所]]で誕生した「[[Self]]」は、Smalltalkの[[クラスベース]]設計をより柔軟に平易化した[[プロトタイプベース]]を編み出している。 |
|||
ネットワーク技術の発展に連れて、データとメソッドの複合体であるオブジェクトの概念は、[[分散システム]]構築のための基礎要素としての適性を特に見出される事になり、[[IBM|IBM社]]、[[Apple|Apple社]]、[[サン・マイクロシステムズ|サン社]]などが1989年に共同設立した[[Object Management Group|OMG]]は、企業システムネットワーク向け分散オブジェクトプログラミング規格となる[[CORBA]]を1991年に発表した。その前年に[[マイクロソフト|マイクロソフト社]]は[[ウェブアプリケーション]]向けの分散オブジェクトプログラミング技術となる[[OLE]]を発表し、1993年には[[Component Object Model|COM]]と称する[[ソフトウェアコンポーネント]]仕様へと整備した。この[[Component Object Model|COM]]の利用を眼目にしてリリースされた「[[Microsoft Visual C++|Visual C++]]」「[[Visual Basic]]」は[[World Wide Web|ウェブ]]時代の新しいプログラミング様式を普及させる先駆になった。この頃にデータ抽象、データ隠蔽、[[アクセスコントロール]]および[[インタフェース (抽象型)|インターフェース]]によるプログラムの抽象化は、総じて[[カプセル化]]の概念でまとめられるようになった。クラスの[[継承 (プログラミング)|継承]]が最もオブジェクト指向らしい機能と見なされていたのが当時の特徴であった。継承構造を利用した振る舞いサブタイピング及び動的ディスパッチは[[多態性]]という用語に包括された。こうしていわゆるオブジェクト指向の三大要素がやや漠然と確立されている。1996年にサン社がリリースした「[[Java]]」は三大要素が強く意識された[[クラスベース]]であり、その中の分散オブジェクト技術は[[JavaBeans|Beans]]と呼ばれた。類似の技術としてApple社も[[MacOS]]上で[[Objective-C]]などから扱える[[Cocoa]]を開発している。また、1994年から96年にかけて「[[Python]]」「[[Ruby]]」「[[JavaScript]]」といったオブジェクト指向スクリプト言語がリリースされ、従来の[[静的型付け]]に対する[[動的型付け]]と、[[クラスベース]]に対する新しい[[プロトタイプベース]]の認知度を高めている。 |
|||
'''オブジェクト指向プログラミング'''(オブジェクトしこうプログラミング、{{Lang-en-short|''object-oriented programming''}}、略語:OOP)とは、互いに密接な関連性を持つ[[変数 (プログラミング)|データ]]と[[メソッド (計算機科学)|メソッド]]をひとつにまとめて[[オブジェクト (プログラミング)|オブジェクト]]とし、それぞれ異なる性質と役割を持たせたオブジェクトの様々な定義と、それらオブジェクトを相互に作用させる様々なプロセスの設定を通して、プログラム全体を構築するソフトウェア開発手法である。 |
|||
抽象化を旨とするオブジェクト指向ではそのプログラミング自体の抽象化も積極的に推進されている。80年代後半から立ち上げられた[[オブジェクト指向分析設計|オブジェクト指向分析]](OOA)や[[オブジェクト指向設計]](OOD)の各手法から導き出される[[コンセプトモデル|概念モデル]]を、多角的に[[フローチャート|チャート化]]ないし[[ダイアグラム|ダイアグラム化]]するための数々のオブジェクト指向開発方法論が[[OOPSLA]]界隈の識者たちから発表されるようになり、そこで用いられる[[形式言語]]は{{仮リンク|オブジェクトモデリング言語|en|Object-modeling language}}と呼ばれた。これはプログラミングのためのプロトタイプ(ひな型)として重視され、オブジェクト指向では[[モデリング言語]]と[[プログラミング言語]]が並んでソフトウェア開発の両輪になった。1994年にモデリング言語による[[ギャング・オブ・フォー (情報工学)|GOF]][[デザインパターン (ソフトウェア)|デザインパターン]]が初回発表され、これはオブジェクト指向教育で非常に重視されるようになった。1995年にモデリング言語の標準化を企図した[[統一モデリング言語|UML]]が[[OOPSLA]]で初回発表され、1997年に[[Object Management Group|OMG]]の標準モデリング言語として採用された。同年に[[デザインパターン (ソフトウェア)|デザインパターン]]を帰納的に分析して九原則にまとめた[[GRASP]]が発表されている。 |
|||
'''[[オブジェクト指向]]'''という用語自体は、計算機科学者[[アラン・ケイ]]によって生み出されている。1962年公開の言語「[[Simula]]」の設計に印象を受けたケイが咄嗟に口にしたとされるこの造語は、彼が1972年から公開を始めた「[[Smalltalk]]」の言語設計を説明する中で初めて世間に発信された。なお、ケイが示した[[メッセージパッシング]]を中心にするオブジェクト指向は広く認知される事はなく、[[オブジェクト (プログラミング)|オブジェクト]]というプログラム概念を注目させるだけに留まっている。同時にケイの手から離れたオブジェクト指向は[[抽象データ型]]を中心にした解釈へと推移していき、1983年に計算機科学者[[ビャーネ・ストロヴストルップ]]が公開した「[[C++]]」が契機になって、日本では一般にOOPの三大要素と呼ばれる[[カプセル化]]、[[継承 (プログラミング)|継承]]、[[ポリモーフィズム|多態性]]といった[[プログラミングパラダイム|パラダイム]]が確立されている。 |
|||
== 特徴 == |
== 特徴 == |
||
{{独自研究|date=2021-04}} |
|||
現行のオブジェクト指向プログラミングは、1974年に計算機科学者[[バーバラ・リスコフ]]らが提唱した[[抽象データ型]]を基礎的な考え方にする方向性で定着している。[[抽象データ型]]のプログラム実装スタイルを具体的に規定したものが1 - 3であり、日本では一般に三大要素と呼ばれている。これに沿った言語仕様を備えたプログラミング言語がオブジェクト指向準拠と判別されている。4は[[アラン・ケイ]]が重視する元祖的なコンセプトであり、オブジェクト指向の源流思想として蛇足ながら紹介を加える。 |
|||
OOPでは[[クラスベース]]と呼ばれるスタイルが多数派である。他に[[プロトタイプベース]]と呼ばれる後発のスタイルもあるが、こちらは少数派である。クラスベースのOOP言語は、[[Smalltalk]]様式と[[C++]]様式で二分されており{{要出典|date=2021年10月|title=二分されているというのは正しいのかもしれないが、「C++様式」という用語が一般的なのか怪しいのと、出典は要る。 それとここで言う C++様式 かつ 動的型付け である言語の例は?}}、C++様式の方がずっと多数派である。C++様式は、[[静的型付け]]と[[動的型付け]]の分類で大別されている。それらの主な特徴を箇条書きするとこうなる。 |
|||
* [[クラスベース]] - クラスのインスタンス化でオブジェクトを構築する。 |
|||
#[[カプセル化]](''encapsulation'') |
|||
** [[Smalltalk]]様式 - クラスとインスタンスの[[相対性]]を付与してオブジェクトを体系化している。動的型付け中心。[[メッセージパッシング]]による多態性。 |
|||
#[[継承 (プログラミング)|継承]](''inheritance'') |
|||
** [[C++]]様式 - クラス(型)とインスタンス(値)<!--型付け値 ←怪しい用語-->に分離してオブジェクトを体系化している。{{仮リンク|動的ディスパッチ|en|Dynamic dispatch}}による多態性。 |
|||
#[[ポリモーフィズム|多態性]](''polymorphism'') |
|||
*** [[静的型付け]] - オブジェクトの構成解釈(型チェックなど)を主にコンパイル時にする。 |
|||
#[[メッセージ (コンピュータ)|メッセージパッシング]](''message passing'') |
|||
*** [[動的型付け]] - オブジェクトの構成解釈(型チェックなど)を主に実行時にする。 |
|||
* [[プロトタイプベース]] - オブジェクトのクローンでオブジェクトを構築する。クラスとインスタンスの[[相対性]]をオブジェクトから撤廃して、プロトタイプでオブジェクトを体系化している。動的型付け中心。[[動的束縛|動的バインディング]]による多態性。 |
|||
なお、場合によっては C言語などオブジェクト指向を支援しない言語でOOP的なプログラミングが行われることもある<!-- それについての書籍があったはず -->。<!-- OOPの三大要素は「なぜオブジェクト指向で作るのか」など数多くの著作に掲載されており、少なくとも日本では広く知られてると思うので取り合えず外しました。 --> |
|||
=== カプセル化 === |
|||
一定の関連性を持つデータ(変数、プロパティ、フィールド、属性)と、それらを操作するメソッド(関数)をひとまとめにしてオブジェクトとし、外部に対して必要とされるデータとメソッドのみを公開し、それ以外を内部に隠蔽する仕組みがカプセル化と呼ばれる。公開されたデータは外部のメソッドから直接参照または変更する事ができる。公開されたメソッドは外部のメソッドから直接呼び出す事ができる。隠蔽されたデータとメソッドは外部からアクセスされないことが保証され、これは{{仮リンク|情報隠蔽|en|information hiding}}と呼ばれる。メソッドを通してデータを参照または変更する仕組みはデータの抽象化を表現し、これは{{仮リンク|Data Abstraction|en|Abstraction (computer science)|label=データ抽象}}と呼ばれる。データを参照するメソッドはゲッターまたはアクセッサと呼ばれる。データを変更するメソッドはセッターまたはミューテイタと呼ばれる。 |
|||
=== |
=== クラスとインスタンス === |
||
OOPの要点である[[クラス (コンピュータ)|クラス]]は、[[データ構造]]とそれを扱うための操作・振る舞いをひとまとめにした一種の[[モジュール|プログラムモジュール]]機能として定義されており、その実装は[[Simula|Simula67]]由来の[[継承 (プログラミング)|継承]]と動的ディスパッチを加えた[[抽象データ型]]のスーパーセットにされていることが多い。クラスのデータ構造は[[レコード型]]や[[構造体]]に似た書式で定義されることが多く、データ構造の要素は言語ごとに[[フィールド (計算機科学)|フィールド]]、[[プロパティ (プログラミング)|プロパティ]]、[[属性]]、メンバ変数などと呼ばれている。クラスに定義される操作・振る舞いは[[メソッド (計算機科学)|メソッド]]やメンバ[[関数 (プログラミング)|関数]]などと呼ばれる。{{要説明|date=2021年10月|title=クラスは (オブジェクトの)分類 という話があるべき。}} |
|||
既存オブジェクトのデータ構成とメソッド構成を引き継いで、新しい派生オブジェクトを定義する仕組みが継承と呼ばれる。引き継ぐ際には新たなデータとメソッドを自由に追加できるので、派生オブジェクトの構成は既存要素+追加要素になる。既存の基底オブジェクトは親オブジェクト、その派生オブジェクトは子オブジェクトとも呼ばれる。クラスベースでは、親をスーパークラス、子をサブクラスと呼ぶ。一つのスーパークラスを継承するのは単一継承と呼ばれる。複数個のスーパークラスを継承してそれぞれの要素を引き継ぐのは多重継承と呼ばれる。[[統一モデリング言語|UML]]では汎化と特化の関係で表現されている。メソッドの抽象化に焦点を当てた継承の方は{{仮リンク|実装継承|en|3=https://en-two.iwiki.icu/wiki/Inheritance_(object-oriented_programming)#:~:text=Implementation%20inheritance%20is%20the%20mechanism,class%20implementation%20with%20its%20own.}}などと呼ばれる。UMLでは実現と実装の関係で表現されている。実装継承は特定のオブジェクトたちに共通した振る舞い側面を抜き出して抽象化する仕組みを指し、その抽象化オブジェクトは[[インタフェース (抽象型)|インターフェース]]、[[トレイト]]、{{仮リンク|プロトコル(OOP)|en|Protocol (object-oriented programming)|label=プロコトル}}などと呼ばれる。 |
|||
OOP言語の[[クラス (コンピュータ)|クラス]]と、そうでない言語での[[モジュール]]の違いを知ることは、OOPを理解する上でも重要になる。どちらも[[プロシージャ|手続き]]と[[データ]]の複合体であるが、クラスの第一の特徴はそれに[[継承 (プログラミング)|継承]]が備えられていることであり、次に[[This (プログラミング)|This参照]]の機構と、[[継承 (プログラミング)|継承]]構造上の[[内包と外延|内包]]的な{{仮リンク|動的ディスパッチ|en|Dynamic dispatch}}である。その次になる{{仮リンク|情報隠蔽|en|information hiding}}と、定義と実装に分離しての[[抽象化 (計算機科学)|抽象化]]の機構は、OOP以前の{{仮リンク|モジュラルプログラミング|en|Modular programming}}からのものである。振る舞い抽象を担っている[[インタフェース (抽象型)|インターフェース]]の概念もそちらが先例であったが、データ抽象を担っている[[カプセル化]](情報隠蔽とThis参照の融合)の採用はOOPが最初である。[[継承 (プログラミング)|継承]]構造上の内包的な動的ディスパッチによる[[派生型|サブタイピング]](=[[ポリモーフィズム]])はOOP発祥であるが、それを純粋化すると前述の[[インタフェース (抽象型)|インターフェース]]になる。OOP以前の[[構造化分析設計技法|構造化開発]]のモジュールには情報隠蔽はあるが、[[継承 (プログラミング)|継承]]はなく、[[カプセル化]]や[[ポリモーフィズム]]といった抽象化の諸機構も持たない。なお、{{仮リンク|振る舞いサブタイピング|en|Behavioral subtyping}}は[[多重ディスパッチ]]のOOPでは軽視されており、カプセル化は[[動的型付け]]のOOPではしばしば軽視されている。 |
|||
=== 多態性 === |
|||
異なる種類のオブジェクトに同一の操作インターフェースを持たせる仕組みが多態性と呼ばれる。オブジェクト指向下の多態性は、クラスの派生関係またはオブジェクトの動的バインディング機能によって、コンパイル時のメソッド名から呼び出されるプロセス内容が実行時に決定されるという仕組みの{{仮リンク|振る舞いサブタイピング|en|Behavioral subtyping}}を指す。これは{{仮リンク|サブタイプ多相|en|Subtyping}}の一種である。その代表格は{{仮リンク|仮想関数(OOP)|en|Virtual function|label=仮想関数}}であり、オブジェクト指向で多態性と言えばこれを指して説明されることが多い。仮想関数は、メソッドが所属するクラスの派生関係のみに焦点を当てた一重ディスパッチであり、スーパークラス抽象メソッドの呼び出しを、それを[[オーバーライド]]したサブクラス実装メソッドの呼び出しにつなげる機能である。一重ディスパッチとはプロセス選択に関与するオブジェクトが一つであることを意味しており、二つ以上の場合は[[多重ディスパッチ]]になる。多重の方はメソッドが属するクラスの派生関係だけでなく、そのメソッドの各引数のクラスの派生関係にも注目した形態であり、各引数は実行時の型判別と[[ダウンキャスト]]されて、その引数型の組み合わせに対応したプロセスを選択する。一重ディスパッチと多重ディスパッチは{{仮リンク|動的ディスパッチ|en|Dynamic dispatch|label=}}という分類用語に包括されており、仮想関数は[[クラスベース]]向けに特化された動的ディスパッチとも定義されている。クラス機構の代わりにプロトタイプ機構を用いる[[プロトタイプベース]]の方では、オブジェクト(フレーム)のメソッド名スロットに当てはめられるメソッド実装の参照が随時切り替えられることにより、そのメソッド名から呼び出されるプロセスが実行時に決定されるという仕組みで広義の振る舞いサブタイピングを表現している。この仕組みも動的ディスパッチという分類用語に包括されており、便宜的にそのまま動的ディスパッチと呼ばれることが多い。 |
|||
C++様式のクラスベースは[[オブジェクト (プログラミング)|オブジェクト]]を、[[型理論]]に沿った{{要出典|date=2021年10月|title=型理論に沿っている と言う必要があるのか疑問だが、書くなら要出典だと思います。}} [[型システム|型]](type)と値(term)に分離している。その型の一種であるユーザー定義型(user defined type)がクラスにされており、クラスで[[型付け]]された値が[[インスタンス]]になっている。ユーザー定義型とは[[構造体]]に似たデータ複合体であり{{疑問点|date=2021年10月}}、OOPでは[[手続き]](のポインタ)もそのメンバにされている。<!-- ユーザー定義型は[[オブジェクト型]]と呼ばれることもあるが、このオブジェクト型と後節の「[[オブジェクト (プログラミング)|オブジェクト]]」の意味上の繋がりはない。←怪しいし中途半端。今の状態ならない方がマシでしょう。-->[[クラス (コンピュータ)|クラス]]はインスタンスのひな型であり、[[インスタンス]]はクラスを実体化したものである。実体化=インスタンス化である。コンパイル時に型チェックされるユーザー定義型は[[静的型付け]]であり、実行時に型チェックされるユーザー定義型は[[動的型付け]]である。なお、Smalltalk様式のクラスベースは[[型理論]]の[[依存型]]に似ている。依存型は型と値の境界がない型付けである。 |
|||
=== メッセージパッシング === |
|||
{{Quotation|''I thought of objects being like biological cells and/or individual computers on a network, only able to communicate with messages.''<br>(さながら生物の細胞、もしくはネットワーク上の銘々のコンピュータ、それらはただメッセージによって繋がり合う存在、僕はオブジェクトをそう考えている)|Alan Kay}}{{Quotation|''... each object could have several algebras associated with it, and there could be families of these, and that these would be very very useful.''<br>(銘々のオブジェクトは自身に伴う幾つかの「代数」を持つ、またそれらの家族たちもいるかもしれない、それらは極めて有用になるだろう)|Alan Kay}}{{Quotation|''The Japanese have a small word - ma ... The key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be.''<br>(日本語には「間」という言葉がある・・・成長的なシステムを作る鍵とは内部の特徴と動作がどうあるべきかよりも、それらがどう繋がり合うかをデザインする事なんだ)|Alan Kay}}{{Quotation|''I realized that the cell/whole-computer metaphor would get rid of data,'' ...<br>(僕はこう気付いた、細胞であり全体でもあるコンピュータメタファーはデータを除去するであろうと、)|Alan Kay}}{{Quotation|''... there were two main paths that were catalysed by Simula. The early one (just by accident) was the bio/net non-data-procedure route that I took. The other one, which came a little later as an object of study was abstract data types, and this got much more play.''<br>(Simulaを触媒にした二本の道筋があった。初めの一本はバイオネットな非データ手法、僕が選んだ方だ。少し遅れたもう一本は抽象データ型、こっちの方がずっと賑わってるね。)|Alan Kay}} |
|||
=== オブジェクトとは === |
|||
== 歴史 == |
|||
[[クラスベース]]言語での「[[オブジェクト (プログラミング)|オブジェクト]]」は、[[インスタンス]]を指す用語として説明されているが、このような重複語になった背景にはOOP原点の[[Smalltalk]]の設計がある。Smalltalkは、全てのプログラム要素は[[オブジェクト (プログラミング)|オブジェクト]]であり、全てのオブジェクトはクラスのインスタンス化であり、クラスもまたオブジェクトであり、オブジェクトは他のオブジェクトと相互作用(interaction)すると定義していた。そこでは[[クラス (コンピュータ)|クラス]]もまた[[メタクラス]](型)の[[インスタンス]]化(値)になり、そのメタクラスもまた他のメタクラスのインスタンス化になっていたので、[[クラス (コンピュータ)|クラス]]と[[インスタンス]]は即ちオブジェクトの性質([[相対性]])を指すための言葉になっていた。これが[[C++]]様式では簡素化されて、クラスとインスタンスは[[型システム|型]]と[[型付け|値]]の役割に固定され、メタクラスは[[リフレクション (情報工学)|リフレクション]]機能に固定されたので、クラスとインスタンス化の[[相互再帰]]が失われたオブジェクトは、相互作用できるインスタンスを指しているままで放置された。相互作用とは各種演算と同義であり、Smalltalkのクラスは相互作用できる値でもあるのでオブジェクトであるが、C++様式のクラスはただの型なので演算対象に出来ないことからオブジェクトではなくなっている。 |
|||
1954年に初の[[高水準言語]]・[[FORTRAN]]が登場すると、開発効率の劇的な向上と共にソフトウェア要求度も自然と高まりを見せてプログラム規模の急速な拡大が始まった。それに対応するために肥大化したメインルーチンを[[サブルーチン]]に分割する手法と、[[スパゲティプログラム|スパゲティ化]]した[[Goto文|goto命令]]を[[制御構造|制御構造文]]に置き換える手法が編み出され、これらは1960年に公開された言語「[[ALGOL|ALGOL60]]」で形式化された。当時のALGOLは[[アルゴリズム]]記述の一つの模範形と見なされたが、それと並行して北欧を中心にした計算機科学者たちはより大局的な観点によるプログラム開発技法の研究を進めていた。 |
|||
Smalltalk方言の[[Self]]を原点とする[[プロトタイプベース]]は、オブジェクトからクラスとインスタンスの[[相対性]]を無くしたスタイルである。数値・文字列・配列・関数・シンボル・[[構造体]]([[オブジェクト型]])といった[[プリミティブ型|基本的な型]]は備えられているが、これはオブジェクト種類の区別に特化されたものなので、[[型理論]]に沿ったクラスベースの[[型システム|それ]]とは厳密には異なっている。クラス性質を除去したオブジェクトは事実上のインスタンスに一元化されており、その全てが相互作用(interaction)する。オブジェクトの表現はスロット(シンボルとコンテンツのペアデータ)の[[可変長配列]]でなされており、オブジェクトの識別は専ら[[ダックタイピング]]によってなされる。クラス概念が無いのでサブクラス化とインスタンス化は成立せず、代わりにクローン(複製)によってオブジェクトの継承がなされており、クローンはインスタンス化の代替になる。複製元オブジェクトは、複製先オブジェクトのプロトタイプと呼ばれる。 |
|||
=== Simulaの開発(1962 - 72) === |
|||
1962年、ノルウェー計算センターで[[モンテカルロ法]]シミュレーションを運用していた計算機科学者[[クリステン・ニゴール]]は、[[ALGOL|ALGOL60]]を土台にしてProcessと呼ばれる[[コルーチン]]機構を加えたプログラミング言語「[[Simula]]」を公開し、続けてその拡張にも取り組んだ。ニゴールの同僚で、1963年にSimulaを[[メインフレーム|汎用機]][[UNIVAC I|UNIVAC]]系統上で運用できるように実装した計算機科学者[[オルヨハン・ダール]]は、Processにローカル変数構造を共有する複数の手続き(サブルーチン)を加えてパッケージ化する言語仕様を考案した。程なくしてALGOL60コンパイラに準拠していての限界を悟ったニゴールとダールは、1965年からSimulaを一から再設計するように方針転換した。その過程で彼らは、計算機科学者[[アントニー・ホーア]]が考案して1962年のSIMSCRIPT([[FORTRAN]]用のスクリプト)に実装していたRecord Classを参考にしている。Record Classはソースコード水準の抽象表現を、各[[メインフレーム|汎用機]]に準拠した[[マシンコード]]水準の実装符号に落とし込む段階的データ構造のプログラム概念であった。これをモデルにした[[継承 (プログラミング)|継承]]とその構造上に成り立つ仮想手続き(仮想関数)の仕組みも考案され、この両機能を備えたProcessのパッケージ化を「[[クラス (コンピュータ)|クラス]]」とし、クラスをメモリに展開したものを「[[オブジェクト (プログラミング)|オブジェクト]]」とする言語仕様がまとまり、1967年に「[[Simula|Simula67]]」が初公開された。オブジェクトという用語は、[[MIT]]の計算機科学者[[アイバン・サザランド]]が1963年に開発した[[Sketchpad]]([[CAD]]と[[GUI]]の元祖)の設計内にあるObjectが先例であった。Simula67コンパイラはまず[[UNIVAC I|UNIVAC]]上で運用され、翌年から汎用機[[バロース B5000|バロースB5500]]などでも稼働されて北欧、ドイツ、ソ連の各研究機関へと広まり、1972年には[[IBMメインフレーム|IBM汎用機]][[System/360]]などにも導入されて北米全土にも広まった。その主な用途は物理シミュレーションであった。 |
|||
<!-- === オブジェクト指向の三大要素 === --> |
|||
=== 構造化プログラミングの提唱(1969 - 75) === |
|||
=== [[カプセル化]] === |
|||
[[Simula]]の普及と前後して1960年代半ばになると、プログラム規模の際限ない肥大化に伴う開発現場の負担増大が顕著になり、いわゆる[[ソフトウェア危機]]問題が計算機科学分野全般で取り沙汰されるようになった。その解決に取り組んだ計算機科学者[[エドガー・ダイクストラ]]は、1969年のNATOソフトウェア工学会議で「[[構造化プログラミング]]」という論文を発表し[[トップダウン設計とボトムアップ設計|トップダウン設計]]、段階的な[[抽象化 (計算機科学)|抽象化]]、階層的な[[モジュール化]]、共同詳細化(抽象データ構造と抽象ステートメントのjoint)といった構造化手法を提唱した。ダイクストラの言う構造化とは開発効率を高めるための[[分割統治法]]を意味していた。なおこの構造化プログラミングは後に曲解されて[[制御構造|制御構造文]]を中心にした解釈の方で世間に広まり定着している。共同詳細化は抽象データ構造を専用ステートメントを通して扱うという概念である。これはSimulaの手続きを通してクラス内の変数にアクセスするという仕組みをモチーフにしていた。段階的な抽象化と階層的なモジュール化は時系列的にも、SIMSCRIPTの段階的データ構造と、Simura67の継承による階層的クラス構造を模倣したものであった。[[エドガー・ダイクストラ|ダイクストラ]]、[[アントニー・ホーア|ホーア]]、[[オルヨハン・ダール|ダール]]の三名は1972年に『構造化プログラミング』と題した共著を上梓していることから互いの研鑽関係が証明されている。その階層的プログラム構造という章の中でダールは、Simulaの目指した設計を更に明らかにした。{{Quotation|''influenced by Sketchpad, Simula, the design for the ARPAnet, the Burroughs B5000, and my background in Biology and Mathematics, I thought of an architecture for programming.'' |
|||
データ構造とそれを扱うためのメソッド群を情報隠蔽の概念と合わせてモジュール化(パッケージ化)するという手法が[[カプセル化]]と呼ばれる。カプセル化されたメソッドは、[[This (プログラミング)|This値]]が暗黙の先頭引数として常に渡されるように実装される。This値とはクラスのデータ構造をメモリ展開するための[[ヒープ領域]]の基底アドレスを指しており、インスタンス化時に確定されたThis値によってメソッドは専用のデータ構造にアクセスできる。専用メソッドを通してのデータ構造の閲覧と変更は、[[抽象データ型]]の考え方に沿ったデータ構造の抽象化を意味することになり、これは{{仮リンク|Data Abstraction|en|Abstraction (computer science)|label=データ抽象}}と呼ばれる。データ閲覧用メソッドはゲッター/アクセッサと呼ばれ、データ変更用メソッドはセッター/ミューテイタと呼ばれる。 |
|||
<br>([[Sketchpad]]、[[Simula]]、[[アーパネット]]、[[バロース B5000|バロースB5000]]、それと専攻していた生物学と数学に影響されて僕はプログラミングアーキテクチャを思索していた)|Alan Kay}}1974年に[[MIT]]の計算機科学者[[バーバラ・リスコフ]]とステファン・ジルは「[[抽象データ型]]」というプログラム概念を提唱した。彼女らの理論は、ダイクストラが提示したモジュールの共同詳細化を、その振る舞いによって[[セマンティクス|意味内容]]が定義される抽象データという考え方でより明解に形式化し、データ階層ないしモジュール階層の連結関係を、[[上位概念、下位概念、同位概念および同一概念|上位概念と下位概念]]の[[リスコフの置換原則|置き換え原則]]で明確に標準化した。一方、1970年に構造化言語[[Pascal]]を開発していた計算機科学者[[ニクラウス・ヴィルト]]は、ダイクストラによる共著出版後の1975年にモジュール化言語[[Modula-2|Modula]]を提示してモジューラプログラミングというパラダイムを生み出している。このようにいささか奇妙ではあるが、Simulaのクラスとオブジェクトというプログラム概念は、巷で言われる構造化からモジュール化へといった進化の流れとは関係なく、しかもその前段階においてさながら彗星のように生まれたパラダイムであった。 |
|||
{{仮リンク|情報隠蔽|en|information hiding}}とはそのクラスのデータ構造の各要素および各メソッドを必要に応じて内部隠蔽するという概念である。内部隠蔽されたデータ要素とメソッドはそのクラス外部からのアクセスが禁止される。[[抽象データ型]]本来の形式ではデータ構造のみが隠蔽対象になるので、これはデータ隠蔽とも呼ばれる。隠蔽指定外のデータ要素とメソッドは外部公開されて、そのクラス外部からもアクセス可能になる。外部公開の範囲を指定する機能は[[アクセスコントロール]]と呼ばれており、これが内部隠蔽の仕組みを担っている。クラスの[[レキシカルスコープ]]を基準にした段階的なアクセス許可範囲は可視性と呼ばれる。可視性は無制限・任意クラスグループ限定・派生クラスグループ限定・自クラス限定(内部隠蔽)の四段階が[[統一モデリング言語|UML]][[クラス図]]では標準にされている。 |
|||
=== Smalltalkとオブジェクト指向の誕生(1972 - 81) === |
|||
SimulaのProcessおよび67年版からのクラスの仕様は、[[パロアルト研究所]]の計算機科学者[[アラン・ケイ]]によるオブジェクトと「メッセージ」というプログラム概念のヒントになった。ケイはプログラム内のあらゆる要素をオブジェクトとして扱い、オブジェクトはメッセージの送受信でコミュニケーションするという独特のプログラム理論を提唱した。メッセージとはプログラムコードとしても解釈できるデータ列のことであり、そのデータ列を評価(''eval'')することで新たなデータを導出できるという仕組みを意味していた。オブジェクトが受け取ったメッセージは任意のタイミングで評価できるので非同期通信、単方向通信(送りっぱなし処理)をも可能にしていた。この発想の背景には[[LISP]]の影響があった。オブジェクトとメッセージの構想に基づいて開発された「[[Smalltalk]]」はプログラミング言語と[[GUI]]運用環境を併せたものとなり、1972年に[[Alto|ゼロックスAlto]]上で初稼働された。Smalltalkの設計を説明するためにケイが考案した「[[オブジェクト指向]]」という用語はここで初めて発信された。またメッセージの構想は[[MIT]]の計算機科学者[[カール・ヒューイット]]に能動的な[[プロセス代数]]を意識させて、1973年発表の[[アクターモデル]]のヒントにもなっている。しかし、データ列が常にコード候補として扱われる処理系は、当時のコンピュータには負荷が大きく実用的な速度を得られないという問題にすぐ直面した。Smalltalk-74とSmalltalk-76の過程で、やむなくメッセージはセレクタ仕様の追加と共に構想通りの評価ができないほどシステム向けに最適化され、レシーバーは動的ディスパッチとメソッド仕様が中心になり、オブジェクトはクラス定義の存在感が大きくなった。{{Quotation|''Smalltalk is not only NOT its syntax or the class library, it is not even about classes. I'm sorry that I long ago coined the term "objects" for this topic because it gets many people to focus on the lesser idea.The big idea is "messaging".'' |
|||
<br>(Smalltalkはその構文やライブラリやクラスをも関心にしていないという事だけではない。多くの人の関心を小さなアイディアに向かせたことから、僕はオブジェクトという用語を昔作り出したことを残念に思っている。大切なのはメッセージングなんだ。)|Alan Kay}}1980年のSmalltalk-80は、元々はメッセージを重視していたケイを自嘲させるほど同期的で双方向的で手続き的なオブジェクト指向へと変貌していた。それでも動的ディスパッチと[[委譲]]でオブジェクトを連携させるスタイルは画期的であり、1994年に発表される[[デザインパターン (ソフトウェア)|デザインパターン]]の模範にもされている。1981年に大手専門誌[[Byte (magazine)|BYTE Magazine]]がSmalltalkとケイ提唱のオブジェクト指向を紹介して世間の注目を集める契機になったが、ケイの思惑に反して技術的関心を集めたのはクラス機構の方であった。オブジェクト指向は知名度を得るのと同時に、Simula発の[[クラス (コンピュータ)|クラス]]とそれを理論面から形式化した[[抽象データ型]]を中心に解釈されるようになり、それらの考案者がケイの構想とは無関係であったことから、オブジェクト指向の定義はケイの手を離れて独り歩きするようになった。 |
|||
=== [[継承 (プログラミング)|継承]] === |
|||
=== C++の開発(1979 - 88) === |
|||
既存クラスのデータ/メソッド構成に、任意のデータ/メソッド構成を付け足して、既存構成+新規構成の新しいクラスを定義するという手法が[[継承 (プログラミング)|継承]]と呼ばれる。また、各クラスの共通構成パートを括りだして特有構成パートと分離することでオブジェクトを分類体系化し、同時にその共通構成パートの記号化によってソースコード内の重複記述を削減する機能とも解釈される。これは差分プログラミング目的の継承であり、実装継承(implementation inheritance)とも呼ばれた。 |
|||
[[Simula]]を研究対象にしていた[[ベル研究所|AT&Tベル研究所]]の計算機科学者[[ビャーネ・ストロヴストルップ]]は、1979年からクラス付きC言語の開発に取り組み、1983年に「[[C++]]」を公開した。C++で実装された[[クラス (コンピュータ)|クラス]]は、Simula譲りの[[継承 (プログラミング)|継承]]と仮想関数に加えて、[[レキシカルスコープ]]の概念をクラス定義とその継承構造に応用したアクセスコントロールを備えていた。C++で確立されたアクセスコントロールはカプセル化の元になったがコードスタイル上ほとんどザル化されており、その理由からストロヴストルップ自身もC++は正しくない(''not just'')オブジェクト指向言語であると明言している。1986年にソフトウェア技術者[[バートランド・メイヤー]]が開発した「[[Eiffel]]」の方は、正しいオブジェクト指向を標榜してクラスのデータ抽象を遵守させるコードスタイルが導入されていた。クラスメンバ(フィーチャー)は属性、手続き、関数の三種構成で、手続きで属性を変更し関数で属性を参照するという形式に限定されており、これは抽象データ型の[[セマンティクス|振る舞い意味論]]に沿った実装であった。アクセスコントロールはC++のアクセス修飾子による段階的レキシカルスコープ定義に対して、自身のクライアントクラスを定義する書式になり、これはモジューラプログラミングの情報隠蔽論に沿った実装であった。C++の仮想関数は延期フィーチャーとして実装された。{{Quotation|''I made up the term ‘object-oriented’, and I can tell you I didn’t have C++ in mind.'' |
|||
<br />(僕はオブジェクト指向という言葉を作った、それとC++に関心がなかったことも分かっている)|Alan Kay}}1986年から[[Association for Computing Machinery|ACM]]が[[OOPSLA|オブジェクト指向会議]](OOPSLA)を開催し、そのプログラミング言語セクションでは[[抽象データ型]]の流れを汲む[[クラス (コンピュータ)|クラス]]・パラダイムが主要テーマにされ、それを標準化するための数々のトピックが議題に上げられている。[[モジュール性]]、情報隠蔽、[[抽象化 (計算機科学)|抽象化]]、再利用性、階層構造、複合構成、実行時多態、動的束縛、[[ガベージコレクション|自動メモリ管理]]といったものがそうであり、参画した識者たちによる寄稿、出版、講演を通して世間にも広められた。[[契約による設計]]を提唱するメイヤーが1988年に刊行した『オブジェクト指向ソフトウェア構築』は名著とされ、Eiffelを現行の模範形とする声も多く上がった。ただしこれは学術寄りの意見でもあったようで、世間のプログラマの間では厳格なEiffelよりも柔軟で融通の利くC++の人気の方が高まっていた。また、Smalltalkが提唱するメッセージ・メタファも単にオブジェクト指向の発案元であるという理由から一目置かれており、クラスのメソッド呼び出しをオブジェクトにメッセージを送ることになぞらえる考えが広まった。これは実行時の選択メソッドをメッセージの発送先にする意味合いで動的(一重と多重)ディスパッチの呼称の由来になっている。他方でSmalltalkの仕様に忠実であろうとする動きもあり、1984年に計算機科学者ブラッド・コックスが開発した「[[Objective-C]]」はSmalltalkをモデルにしてそれを平易化した言語であった。そのメッセージレシーバーはメソッドリストにないセレクタを受け取った場合にのみ動的ディスパッチ機構に移るというスタイルで形式化された。程なくしてこのメッセージレシーバー実装の必要性には疑問符が付けられるようになったが、[[遠隔手続き呼出し]]のスタイルにはマッチしていたのでメッセージにある種の理想を抱く風潮はいつまでも残った。 |
|||
[[リスコフの置換原則|リスコフ置換原則]]と[[開放/閉鎖原則]]が取り上げられると、既存構成に抽象メソッドを置いて新規構成にその実装メソッドを置くという[[オーバーライド|メソッドオーバーライド]]を用いるための{{仮リンク|振る舞いサブタイピング|en|Behavioral subtyping}}目的の継承の方が重視されるようになり、これは界面継承(interface inheritance)とも呼ばれた。メソッド定義の引き継ぎと[[サブタイプ|サブタイピング]]を中心にした[[Is-a]]関係主体の継承をUML[[クラス図]]は特化(specialization)と定義している。 |
|||
=== プロトタイプベースの考案(1985 - 90) === |
|||
[[Smalltalk]]のオブジェクト指向は、[[アラン・ケイ]]がその影響を言及していた[[LISP]]コミュニティを逆に感化して、Smalltalkが提示したメタオブジェクトの概念を通したオブジェクト指向とLISP風プログラミングの連携に向けた構想が練られるようになった。LISPの基礎であるアトムとシンボル型に倣う形で、オブジェクトのメンバ変数名とメンバ関数名自体をその都度評価(''eval'')して実行時の内容を導出し、実際の変数参照や関数呼出につなげるというアイディアが生まれた。これは実装面では単に、フレームと呼ばれる動的配列のスロットに変数や関数のポインタを付け替えするという機構にまとめられた。識別子(変数名と関数名)がマッピングされたスロットも増設削減可能であり、原型クラスと継承クラスのポインタも加えられた。このメタオブジェクト設計を導入して1985年に[[MIT人工知能研究所]]の[[LISPマシン]]上で「Flavors」が実装された。LISPの視点から保有スロット識別子の構成による[[動的型付け]]が盛り込まれ、その構成をパーツ化して多重継承させる[[ミックスイン]]という設計が考案され、また実行時の逐次型判別に焦点を当てた[[ダックタイピング]]の概念も生まれた。1988年にFlavorsのデザインを[[Common Lisp]]に融合させた「[[CLOS]]」が公開されたが、こちらは関数を中心にして抽象データ型から距離を置いたスタイルになった。Flavorsのデザインは[[パロアルト研究所]]にも回帰され、計算機科学者デビッド・アンガーがSmalltalkの方言として制作する「[[Self]]」を1987年に初回稼働して90年に一般公開した。LISPコミュニティから逆輸入されてSelfに導入されたメタオブジェクト設計は、後に[[プロトタイプベース]]またはインスタンスベースと呼ばれるパラダイムに発展する。同時にそれと、従来の[[クラス (コンピュータ)|クラス]]機構を中心にしたオブジェクト指向言語を区別するための[[クラスベース]]という言葉も生まれた。 |
|||
既存クラスはスーパークラス・親クラス・基底クラスなどと呼ばれ、新しいクラスはサブクラス・子クラス・派生クラスなどと呼ばれる。親と子は差分プログラミング重視で、基底と派生はサブタイピング重視で用いられる。継承できるクラスが一つに限られている単一継承を採用している言語と、継承できるクラスの数に制限がない多重継承を採用している言語がある。<!--概念的に インターフェース継承(型継承、[[is-a関係]]、下位分類)と 実装の継承 の2つの側面があるといったことを書いた方がよさそう。 記述によっては両方の継承関係が同時に生じる。-->抽象メソッドを持つクラスは抽象クラスと呼ばれる。基底クラス側でリターン型とパラメータのみが定義されて実行コードブロックが未定義のままの抽象メソッドは、その派生クラス側の実装メソッドで[[オーバーライド]]される。オーバーライドは遅延結合による多相な[[複雑系]][[アルゴリズム]]を表現するオープン[[再帰]](open recursion)のメカニズムにもなっている。 |
|||
=== コンポーネントとネットワーク(1989 - 97) === |
|||
ネットワーク技術の発展に連れて、データとメソッドの複合体であるオブジェクトの概念は、[[分散システム]]構築のための基礎要素としての適性を特に見出される事になり、[[IBM|IBM社]]、[[アップル (企業)|アップル社]]、[[サン・マイクロシステムズ|サン社]]などが1989年に共同設立した[[Object Management Group|OMG]]は、企業システムネットワーク向け分散オブジェクトプログラミングの標準規格となる[[CORBA]]を1991年に公開した。その前年に[[マイクロソフト|マイクロソフト社]]は[[ウェブアプリケーション]]向けの分散オブジェクト技術となる[[OLE]]を発表し、1993年には[[Component Object Model|COM]]と称する[[ソフトウェアコンポーネント]]仕様へと整備した。この[[Component Object Model|COM]]の利用を眼目にしてリリースされた「[[Microsoft Visual C++|Visual C++]]」「[[Visual Basic]]」は[[World Wide Web|ウェブ]]時代の新しいプログラミングスタイルを普及させる先駆になった。この頃に[[抽象データ型]]のメソッドを通したデータ抽象、データ隠蔽、[[アクセスコントロール]]および分散オブジェクト=[[プロセス間通信]]の[[インタフェース (情報技術)|インターフェース]]機構によるプログラムの抽象化といった概念は、[[カプセル化]]という用語にまとめられるようになった。クラスの[[継承 (プログラミング)|継承]]が最もオブジェクト指向らしい機能と見なされていたのが当時の特徴であり、深い継承構造を技巧的と見る風潮さえ存在した。継承構造を利用したサプタイピングは[[多態性]]という用語に包括され、多重継承の欠点が指摘されると分散オブジェクトのそれに倣った[[インタフェース (抽象型)|インターフェース]]の多重実装設計が取り上げられた。こうしてカプセル化の誕生と連動するようにしていわゆるオブジェクト指向の三大要素がやや漠然と確立されている。1996年にサン社がリリースした「[[Java]]」は三大要素が強く意識された[[クラスベース]]であり、その中の分散オブジェクト技術は[[JavaBeans|Beans]]と呼ばれた。類似の技術としてアップル社も[[MacOS]]上で[[Objective-C]]などから扱える[[Cocoa]]を開発している。また、1994年から96年にかけて「[[Python]]」「[[Ruby]]」「[[JavaScript]]」といったオブジェクト指向スクリプト言語がリリースされ、[[プロトタイプベース]]という新しいプログラミングスタイルを定着させている。1994年のGOF[[デザインパターン (ソフトウェア)|デザインパターン]]の発表と1997年の[[Object Management Group|OMG]]による[[統一モデリング言語|UML]]策定は、オブジェクト指向プログラミングの標準化を促進させた。 |
|||
抽象メソッドのみで構成される純粋抽象クラスは[[インタフェース (抽象型)|インターフェース]]と呼ばれ、その継承をUML[[クラス図]]は実装(implementation)と定義している。インターフェースの実装は、[[サブタイプ|サブタイピング]]の[[Is-a]]関係を完全順守させるメカニズムである。また、クラスへの機能注入を目的にして、主に具象メソッド群をクラスに継承させるというアプローチもあり、これは[[ミックスイン]](mix-in)と呼ばれる。mix-inのメソッド集合体は、[[トレイト]]の形態にされることが多い。mix-inはUML[[クラス図]]では扱われていない継承関係である。 |
|||
== 代表的なオブジェクト指向言語 == |
|||
オブジェクト指向言語は、[[抽象データ型]]の仕組みに沿った[[クラスベース]]、メタオブジェクトの仕組みに沿った[[プロトタイプベース]]、[[Smalltalk]]をルーツにした[[メッセージパッシング|メッセージ]]構文ベースの三タイプに分類されるのが一般的である。[[クラスベース]]では「C++」「Java」「C#」が代表的である。[[プロトタイプベース]]では「Python」「JavaScript」「Ruby」が有名である。[[メッセージパッシング|メッセージ]]構文ベースでは「Smalltalk」「Objective-C」「Self」などがある。言語仕様の中でオブジェクト指向の存在感が比較的高い代表的なプログラミング言語は以下の通りである。 |
|||
[[ファイル:History of object-oriented programming languages.svg|境界|中央|フレームなし]] |
|||
;[[Simula|Simula 67]] 1967年 |
|||
:1962年に公開された[[Simula]]の後継版であり、[[クラス (コンピュータ)|クラス]]のプログラム概念を導入した最初の言語である。物理モデルを解析するシミュレーション制作用に開発されたもので、クラスをメモリに展開したオブジェクトはその観測対象要素になった。Simulaのクラスは、一つのローカル変数構造と複数のプロシージャをまとめたミニモジュールと言えるものであったが、継承と仮想関数という先進的な設計を備えていた事でオブジェクト指向言語の草分けと見なされるようになった。[[クラスベース]]の源流である。 |
|||
;[[Smalltalk]] 1972年 |
|||
:[[メッセージパッシング]]のプログラム概念を導入した最初の言語。数値、真偽値、文字列から変数、コードブロック、メタデータまでのあらゆる要素をオブジェクトとするアイディアを編み出した最初の言語でもある。オブジェクト指向という言葉はSmalltalkの言語設計を説明する中で生み出された。オブジェクトにメッセージを送るという書式であらゆるプロセスを表現することが目標にされている。[[メッセージ転送|メッセージレシーバー]]と[[委譲]]の仕組みは、形式化されていない動的ディスパッチと[[ダイナミックバインディング|動的バインディング]]相当のものであり[[プロトタイプベース]]の源流にもなった。GUI運用環境に統合された専用のランタイム環境上で動作させる設計も模範にされ、これは後に[[仮想マシン]]や[[仮想実行システム]]と呼ばれるものになる。 |
|||
;[[C++]] 1983年 |
|||
:[[C言語]]に[[クラスベース]]のオブジェクト指向を追加したもの。Simulaの影響を受けている。[[静的型付け]]の[[クラス (コンピュータ)|クラス]]が備えられてカプセル化、継承、多態性の三仕様を実装している。カプセル化ではアクセス修飾子とフレンド指定子の双方から可視性を定義できる。継承は多重継承、オーバーライド制約用の継承可視性、[[菱形継承問題]]解決用の[[仮想継承]]も導入されている。多態性は[[仮想関数]]によるサブタイプ多相、[[テンプレート (プログラミング)|テンプレートクラス&関数]]によるパラメトリック多相、[[多重定義|関数&演算子オーバーロード]]によるアドホック多相が導入されている。元がC言語であるため、オブジェクト指向から逸脱したコーディングも多用できる点が物議を醸したが、その是非はプログラマ次第であるという結論に落ち着いた。 |
|||
;[[Objective-C]] 1984年 |
|||
:[[C言語]]に[[メッセージパッシング|メッセージ]]構文ベースのオブジェクト指向を追加したもの。こちらはSmalltalkの影響を受けており、それに準じた[[メッセージパッシング]]の書式が備えられた。メッセージを受け取るクラスの定義による[[静的型付け]]と共に、メッセージを[[委譲]]するオブジェクトの実行時決定による[[動的型付け]]も設けられている。オブジェクト指向的にはC++よりも正統と見なされた。[[制御構造|制御構造文]]が追加され、メッセージを送る書式も平易化されており、Smalltalkよりも扱いやすくなった。 |
|||
;[[Object Pascal]] 1986年 |
|||
:[[Pascal]]にクラスベースのオブジェクト指向を追加したもの。当初はモジュールのデータ隠蔽的なカプセル化、単一継承、仮想関数による多態性という基本的なものだった。静的型付け重視である。[[多重定義|関数&演算子オーバーロード]](アドホック多相)と[[ジェネリックプログラミング|ジェネリクス]](パラメトリック多相)は当初採用に到らなかった。[[ニクラウス・ヴィルト|ヴィルト]]監修の[[アップル (企業)|アップル社]]による初回バージョンを基礎にして様々な企業団体による派生版が公開されており、その特徴と機能追加も様々である。 |
|||
;[[Eiffel]] 1986年 |
|||
:[[C++]]の柔軟性と融通性とは正反対のオブジェクト指向言語。[[クラスベース]]で[[静的型付け]]重視である。[[契約プログラミング|契約による設計]]に基づく[[表明|アサーション]]の挿入でクラスの状態および演算用の引数と返り値を細かくチェックできる。[[例外処理]]も備えられている。クラスメンバ(フィーチャー)はデータ、アクセッサ、ミューテイタの三種限定で[[多重定義|オーバーロード]]はできない。カプセル化の可視性は自身に依存するクラス(クライアント)を定義する形で決められる。多重継承可能であり、クラス間の繋がりを[[仮想継承]]機能、各種[[オーバーライド]]指定子、名前衝突を解決するリネーミング機能などで綿密に設定できる。仮想関数と[[ジェネリックプログラミング|ジェネリッククラス]]も導入されている。[[ガーベジコレクション]]機能が初めて導入されたオブジェクト指向言語でもある。 |
|||
;[[Self]] 1987年 |
|||
:[[メッセージパッシング|メッセージ]]構文ベースのオブジェクト指向言語。デフォルト配備のオブジェクトを複製して、そのスロットに任意のプロパティとメソッドを[[ダイナミックバインディング|動的バインディング]]できるという[[プロトタイプベース]]を初めて導入したオブジェクト指向言語でもある。ゆえに[[動的型付け]]重視である。当初はSmalltalkの派生言語として公開されており、それと同様に専用のランタイム環境上で実行され、GUI運用環境の構築も目標にしていた。Selfのランタイム環境は[[実行時コンパイラ]]機能を初めて実装したことで知られており画期的な処理速度を実現している。この技術は[[Java仮想マシン]]の土台になった。 |
|||
;[[CLOS]] 1988年 |
|||
:[[Common Lisp]]に[[プロトタイプベース]]に似たオブジェクト指向を追加したもの。[[構造体]]オブジェクトと[[多重定義|多重定義関数]]オブジェクトに分離されており、前者のスロットには任意のフィールドを、後者のスロットには任意のパラメータパターンを[[ダイナミックバインディング|動的バインディング]]できる動的型付け重視である。動的型付けの構造体オブジェクトを引数として渡される関数の[[多重ディスパッチ]]が重視されている。 |
|||
;[[Python]] 1994年 |
|||
:[[プロトタイプベース]]のオブジェクト指向スクリプト言語。[[基本データ型]]や[[コンテナ (データ型)|コレクション型]]などよく使われるデータ要素を全て組み込みのオブジェクトにしており、[[手続き型プログラミング]]スタイルでの関数の対象値としても扱いやすく、またコレクション型を扱うのに適した[[関数型プログラミング]]構文も導入されている。関数もオブジェクトなので柔軟に扱える。オブジェクトは自由にプロパティとメソッドを付け替えして様々に応用できるようデザインされている。オブジェクトは[[ダックタイピング]]で型判別されるので変数ないし関数の型宣言と型注釈は撤廃されている。ゆえに[[動的な型付け|動的型付け]]重視である。Pythonのプロトタイプオブジェクトはクラスと呼ばれている。多重継承可能であり親要素の参照順序はC3線形化で解決されている。アクセスコントロールはなくデータ抽象を軽視するコードスタイルと相まってカプセル化は備えられていない。多態性はメソッドの動的バインディングで行われる。後期バージョンで型ヒントが追加され、それに伴い[[ジェネリクス]]も導入された。 |
|||
;[[Java]] 1995年 |
|||
:[[C++]]をモデルにしつつ堅牢性とセキュリティを重視した[[クラスベース]]のオブジェクト指向言語。静的型付け重視である。パッケージ中心のカプセル化、単一のみの継承、仮想関数と多重実装可な[[インタフェース (抽象型)|インターフェース]]による多態性と、基本に忠実なクラスベースである。C++の[[ポインタ (プログラミング)|ポインタ]]と値型インスタンスと[[演算子オーバーロード]]は除外され、参照型インスタンスに統一されて[[例外処理]]は残された。クラスメタデータを操作できる[[リフレクション (情報工学)|リフレクション]]は初期から採用された。オブジェクト指向と[[マルチスレッド]]仕様の調和が図られ、[[ソフトウェアコンポーネント|コンポーネント指向]]による動的クラスローディングの存在感が高められている。中期からデータコンテナ系のクラスと関数型インターフェースなどに限って[[ジェネリクス]]が導入されている。[[仮想マシン]]上で実行される。[[仮想マシン]]と[[ガーベジコレクション]]の技術は比較的高度と見なされている。 |
|||
;[[Delphi]] 1995年 |
|||
:[[Object Pascal]]を発展させたもの。それと同様にこちらも基本に忠実なクラスベースで静的型付け重視であった。当初はデータベース操作プログラム開発を主な用途にして公開された。クラスとレコード([[構造体]])に同等の比重が置かれていた。一時期Javaの対抗馬になった。 |
|||
;[[Ruby]] 1995年 |
|||
:[[Python]]を意識して開発されたオブジェクト指向スクリプト言語。[[Smalltalk]]を一つの理想にして動的型付けを重視している。日本で誕生してグローバル化したプログラミング言語である。[[LISP]]とSmalltalkのメタプログラミング的なオブジェクト指向から、Pythonと[[JavaScript]]のプロトタイプベースなオブジェクト指向までのスタイルを幅広く取り入れており、様々な有用なプログラミング手法を採用している技のデパートのような言語である。 |
|||
;[[JavaScript]] 1996年 |
|||
:[[プロトタイプベース]]のオブジェクト指向スクリプト言語。型宣言と型注釈を撤廃して[[ダックタイピング]]する[[動的な型付け|動的型付け]]重視である。すべてをオブジェクトにする[[Smalltalk]]の思想に忠実な言語であり、[[Python]]と似ているがそれよりもプロトタイプベース性と関数型スタイルを追求している。関数とインスタンスをほぼ同等なオブジェクトにしている。返り値無しの関数はnew指定でインスタンス生成用の写像になり、その関数のローカル要素がインスタンスのプロパティとメソッドになる。new指定関数は共通のプロトタイプを持つインスタンス(クローンオブジェクト)を継続生成する。JavaScriptのインスタンスは[[クロージャ]]に近いことから[[高階関数]]も自然表現されて[[関数型プログラミング]]との融合も実現している。[[ウェブアプリケーション|WEBアプリケーション]]開発を主な用途にして公開されたのでオブジェクトは[[GUI]]パーツの構築にも最適化されている。[[ECMAScript]]として標準化されており、2015年版からは[[クラスベース]]向けの構文もサポートするようになった。 |
|||
;[[C Sharp|C#]] 2000年 |
|||
:[[Java]]を強く意識してマイクロソフト社が開発したクラスベースのオブジェクト指向言語。C++の柔軟性と融通的を残しながら、[[テンプレートメタプログラミング]]的なコーディングサポートも加えてマルチパラダイムに発展させている。アドホック多相では拡張メソッド、インデクサ、演算子オーバーロードなどを備えている。パラメトリック多相ではジェネリクスの型変数の[[共変性と反変性 (計算機科学)|共変性と反変性]]、型引数の型制約などを備えている。サブタイプ多相はクラスは単一継承でインターフェースは多重実装と基本通りである。[[関数型言語|関数型構文]]では特にデリゲートの有用性が高い。基本は[[静的型付け]]であるが、動的束縛型と[[ダックタイピング]]による[[動的型付け]]の存在感が高められているので漸進的型付けの言語と見なされている。[[.NET Framework]]([[共通言語基盤]]=仮想実行システム)上で実行される。 |
|||
;[[Scala]] 2003年 |
|||
:[[クラスベース]]のオブジェクト指向と[[関数型プログラミング]]を融合させた言語。[[クラス (コンピュータ)|クラス]]機構と関数型の[[型システム]]に同等の比重が置かれており静的型付け重視である。[[ミックスイン]]相当の[[トレイト]]と[[ジェネリクス]]を連携させた多態性が重視されている。型変数の[[共変性と反変性 (計算機科学)|バリアンス]]、[[共変性と反変性 (計算機科学)|共変と反変]]双方の型境界、抽象タイプメンバ、ジェネリックトレイト、抽象クラスの組み合わせでオブジェクトを様々に[[派生型|派生型付け]]できる。シングルトンオブジェクトの役割が形式化されて従来のクラス静的メンバの新解釈にも用いられている。専用の定義書式により[[イミュータブル]]なオブジェクトが重視されている。上述の派生型付けスタイルとオブジェクトの[[パターンマッチング|パターンマッチング式]]とオブジェクト引数の[[逆写像|抽出]]構文の併用は[[モナド (プログラミング)|モナド]]を彷彿とさせるものであり、[[抽象データ型]]を値として扱う独特の関数型スタイルを表現できる。[[Java仮想マシン]]上で動作するJavaテクノロジ互換言語である。 |
|||
;[[Kotlin]] 2011年 |
|||
:静的型付けの[[クラスベース]]のオブジェクト指向であるが、[[手続き型プログラミング]]に回帰しており、クラス枠外の関数とグローバル変数の存在感が高められている。クラスはpublicアクセスとfinal継承がデフォルトにされて、カプセル化と継承が公然と軽視されている。これによりインスタンスは手続き型の関数の対象値としての役割が強められ、その操作をサポートする関数型構文も導入されている。仮想関数と抽象クラスによる多態性は標準通りである。[[Java仮想マシン]]上で動作するJavaテクノロジ互換言語である。 |
|||
;[[TypeScript]] 2012年 |
|||
:[[JavaScript]]を強く意識してマイクロソフト社が開発したオブジェクト指向スクリプト言語。JavaScriptのプログラムを静的型付けで補完した言語である。[[クラスベース]]向けの構文と、[[関数型プログラミング]]の[[型システム]]のスタイルが加えられている。特に後者の性質が強調されている事から静的型付け重視である。継承構造によるサブタイプ多相はほぼ除外されており、パラメトリック多相とアドホック多相でオブジェクトを扱うという[[ジェネリクス]]とバリアンスと型制約と型注釈を重視するデザインになっている。オブジェクト指向ではあるが関数型の性格が強めである。 |
|||
;[[Swift (プログラミング言語)|Swift]] 2014年 |
|||
:[[Objective-C]]を発展させたものであるが、メッセージ構文は破棄されており、クラスベースのオブジェクト指向になっている。オブジェクトの[[イミュータブル|イミュータブル性]]重視の構文が採用されている。プロテクト可視性の削除によってクラスの縦並びの継承は軽視されており、プロトコルの横並びの多重実装を重視している。プロトコルは[[インタフェース (抽象型)|インターフェース]]と[[ミックスイン]]の中間的機能であり、インスタンスはプロトコルを基準にして型分類され、また抽象化される。プロトコルと[[ジェネリクス]]の連携による多態性が重視されている。モジュールの動的ローディングは不透明型の仕組みで補完されている。[[静的型付け]]重視である。 |
|||
=== [[ポリモーフィズム]] === |
|||
== 用語と解説 == |
|||
異なる種類のクラスに共通の操作インターフェースを持たせてオブジェクトの振る舞いを抽象化するという手法が[[ポリモーフィズム]](多態性)と呼ばれる。OOPで語られる多態性はもっぱら継承構造を利用した{{仮リンク|サブタイプ多相|en|Subtyping}}を対象にしているが、{{仮リンク|アドホック多相|en|Ad hoc polymorphism}}もサポート的に用いられており、{{仮リンク|パラメトリック多相|en|Parametric polymorphism}}はコンポジションで用いられている。そのサブタイプ多相の設計としては、コンパイル時に確定されたメソッド名から呼び出されるプロセス内容が実行時に決定されるという仕組みを指しており、一つのメソッド名からその実行時状態に合わせた個別のメソッド処理が呼び出されるようにするという演繹的意味と、各クラスの同種機能メソッドを一つの共通メソッドにまとめて実行時状態に合わせたメソッド処理が呼び出されるようにするという帰納的意味がある。 |
|||
;[[クラス (コンピュータ)|クラス]] |
|||
:クラス(''class'')の仕組みを中心にしたオブジェクト指向を[[クラスベース]]と言う。クラスはデータメンバとメソッドをまとめたものであり、[[プログラム意味論|操作的意味論]]を付加された静的[[構造体|レコード]]とも解釈される。クラスはインスタンスのひな型になる。クラスはカプセル化、継承、多態性の三機能を備えていることが求められている。カプセル化はデータメンバとメソッドの可視性を指定する機能である。継承は自身のスーパークラスを指定する機能である。多態性はオーバーライドと[[仮想関数テーブル]]を処理する機能である。コンストラクタとデストラクタの実装も必要とされている。前者はインスタンス生成時に、後者はインスタンス破棄時に呼び出されるメソッドである。 |
|||
;プロトタイプオブジェクト |
|||
:プロトタイプ(''prototype'')の仕組みを中心にしたオブジェクト指向を[[プロトタイプベース]]と言う。プロトタイプベースで言われるオブジェクトとは、中間参照ポインタの動的配列を指す。この動的配列は一般にフレームと呼ばれる。中間参照ポインタは一般にスロットと呼ばれる。スロットにはデータメンバとメソッドの参照が代入されるので、オブジェクトはクラスと同様にデータメンバとメソッドをまとめたものになる。プロトタイプベースの実装形式は言語ごとに様々であるが基本は概ね以下のようになる。オブジェクトはプロトタイプオブジェクトとクローンオブジェクトに分かれる。前者はクラス、後者はインスタンスに当たるものである。前者はシステム提供プロトタイプとユーザー定義プロトタイプに分かれる。プログラマはシステム提供プロトタイプを派生させてユーザー定義プロトタイプを作成する。プロトタイプは規定または事前の設計に基づいたデータメンバとメソッドを保持しており、クローンオブジェクトのひな型になる。クローンはそのプロトタイプへの参照を保持しており、プロトタイプはその親プロトタイプへの参照を保持している。これは継承相当の機能になる。プロトタイプを複製してクローンオブジェクトが生成される。クローンオブジェクトはそのプロトタイプと同じデータメンバとメソッドを保持する事になるが、プロトタイプ専用に指定されたメンバは除かれる。クローンオブジェクトのメソッドは自由に付け替えできるので、これは多態性相当の機能になる。 |
|||
;[[メッセージ (コンピュータ)|メッセージ]] |
|||
:オブジェクト指向で言われるメッセージ(''message'')は、複数の方面の考え方が混同されている曖昧な用語になっている。元々はSmalltalkから始まったメッセージ構文ベースのオブジェクト指向の中心機構である。以前はクラスベースの方でもメソッドの呼び出しをメッセージを送るという風に考えることが推奨されていた。メッセージはオブジェクトのコミュニケーション手段と標榜されているが、その忠実な実装内容はそれほど知られていないのが実情である。最も混同されているものに[[アクターモデル]]があるが、そこで言われる非同期性とオブジェクト指向で言われる評価の遅延性は現行の実装スタイルではそれほど共通していない。コンポーネント準拠ソフトウェア工学と[[Object Request Broker|オブジェクトリクエストブローカー]]で言われる[[ソフトウェアコンポーネント]]同士の通信もメッセージパッシングと呼ばれることが多いが、その仕様と機能は動的ディスパッチに該当するものである。メッセージのオブジェクト指向的運用はメッセージングと名付けられている。具体的な機能例としてはSmalltalk、Objective-C、Selfの[[メッセージ転送|メッセージレシーバー]]と、Rubyのメソッドミッシングなどがあるが、いずれもメッセージングの本質ではないとも言われている。 |
|||
;[[インスタンス]] |
|||
:(''instance'')はクラスベースではクラスを実体化(量化)したものであり、実装レベルで言うとデータメンバと仮想関数テーブルをメモリ上に展開したものになる。プロトタイプベースではプロトタイプオブジェクトのクローンで生成されたオブジェクトを指す。実装レベルで言うとメモリ上に展開された中間参照ポインタの動的配列になる。 |
|||
;[[フィールド (計算機科学)|データメンバ]] |
|||
:(''data member'')はクラスまたはオブジェクトに属する変数。言語によってフィールド、プロパティ、メンバ変数、属性と呼ばれる。データメンバは、クラスデータメンバとインスタンスデータメンバに分かれる。クラスデータメンバは静的データメンバとも呼ばれる。その中で定数化されたものはクラス[[定数 (プログラミング)|定数]]と呼ばれる。クラスデータメンバはクラス名の名前空間でスコープされたグローバル変数と同じものであり、プログラム開始時から終了時まで確保される。インスタンスデータメンバはインスタンス生成時にメモリ上に確保されるものであり、その破棄時に消滅する。プロトタイプベースではプロトタイプオブジェクト専用のデータメンバが静的データメンバ相当になる。 |
|||
;[[メソッド (計算機科学)|メソッド]] |
|||
:(''method'')はクラスまたはオブジェクトに属する関数。言語によってはメンバ関数とも呼ばれる。データメンバの参照に特化したものはゲッター(''getter'')アクセッサ(''accessor'')と呼ばれる。データメンバの変更に特化したものはセッター(''setter'')ミューテイタ(''mutator'')と呼ばれる。メソッドは、クラスメソッドとインスタンスメソッドに分かれる。クラスメソッドは静的メソッドとも呼ばれる。クラスメソッドはクラス名の名前空間でスコープされたグローバル関数と同じものである。インスタンスメソッドを呼び出すにはそのインスタンス参照が必要になり、これはthis参照と呼ばれる。プロトタイプベースではプロトタイプオブジェクト専用のメソッドが静的メソッド相当になる。 |
|||
;[[コンストラクタ]] |
|||
:(''constructor'')はインスタンス生成時に呼び出されるそのクラスのメソッドである。インスタンスデータメンバを任意の値で初期化するためのものであるが、その他の初期化コードも記述できる。プロトタイプベースではシステム提供プロトタイプが保持する生成用メソッドまたは生成用のグローバル関数がコンストラクタ相当になる。 |
|||
;[[デストラクタ]] |
|||
:(''destructor'')はインスタンス破棄時に呼び出されるそのクラスのメソッドである。インスタンス破棄の影響を解決する任意の後始末コードを記述できる。インスタンスの破棄は占有メモリの解放を意味する。なお、ガーベジコレクタ実装言語ではファイナライザになっている事がある。プログラマが呼び出すデストラクタの方はその終了がメモリ解放に直結しているのに対し、ガーベジコレクタが呼び出すファイナライザの方はそうではない。 |
|||
;[[This (プログラミング)|this参照]] |
|||
:(''this'')は、言語によっては「self」や「me」とも呼ばれる。インスタンスメソッドを呼び出す時は、このthis参照が暗黙の引数として渡されている。this参照はその該当インスタンスを指すポインタである。そのメソッド内でデータメンバにアクセスする時は、システム内で「this.データメンバ」のように変換されている。データにメソッドを付属させるカプセル化を実現するための仕組みである。 |
|||
;super参照 |
|||
:(''super'')は、継承構造のインスタンスメソッド内で用いられるものであり、現行クラスの直上スーパークラスのメソッドとデータメンバにアクセスするための参照である。オーバーライドやドミナンスを無視して、スーパクラスのメンバを呼び出すための仕組みである。 |
|||
;アクセスコントロール |
|||
:(''access control'')は、カプセル化の情報隠蔽に基づいた機能であり、クラス内のデータメンバとメソッドの可視性を決定するものである。これはレキシカルスコープ基準とクライアント基準の二通りがある。レキシカルスコープ基準の可視性はプライベート、プロテクト、パブリックの三種が基本である。プライベートは同クラス内のみ、プロテクトは同クラス内と派生クラス内のみ、パブリックはどこからでもアクセス可能である。クライアント基準の可視性は自クラス内のメンバへのアクセスを許可するクライアントクラスないしフレンドクラスを定義する方法で決められる。言語によってはクライアントクラス指定は同時にそのサブクラス指定も兼ねている。この場合は継承関係を利用したクラス群の一括クライアント定義が可能である。 |
|||
;コピーコンストラクタ |
|||
:(''copy constructor'')は、メソッドの引数に対する値インスタンスの値渡しの時に呼び出されるコンストラクタである。値渡しはインスタンス内容全体のメモリコピーであり、基本データ型では特に問題は生じないが、そうでないクラスのインスタンスでは例えばあるリソースへの参照を保持している場合に好ましくない保持重複が発生する事になる。呼び出されたコピーコンストラクタは値インスタンスを受け取り、単純コピーが許されない部分に任意の処理を施して生成した値インスタンスのコピーを引数へと渡す。 |
|||
;[[オーバーロード]] |
|||
:(''overloading'')は一つのメソッド名に複数の異なるパラメータリスト(引数欄)を付けたものを列挙してメソッド名を多重定義すること。[[演算子]]もオーバーロード対象であり、[[単項演算子]]なら一つの引数の型、[[二項演算子]]なら二つの引数の型を多重定義することで演算対象の値の型ごとに計算内容をカスタマイズできる。任意数の引数の型を多重定義できる( )演算子は、[[クロージャ]]または[[関数オブジェクト]]の表現に用いられる。アドホック多相とされる。 |
|||
;メソッド拡張 |
|||
:(''method extension'')は、クラス定義とは別の場所でそのクラスに対する追加メソッドを定義できる機能である。これは状況に合わせてデータ抽象の表現に幅を持たせることを目的にしている。これには数々の書式があるが代表的なのは、静的メソッドまたは静的関数の第1引数をthis修飾して、その第1引数のクラス(型)に対してその静的メソッドをインスタンスメソッドとして追加するというものである。静的メソッドはそのクラススコープ内の限定拡張にできる。静的関数はネスト関数にしてそのローカルスコープ内の限定拡張にできる。双方はグローバル用途にすることもできる。アドホック多相とされる。 |
|||
;[[オーバーライド]] |
|||
:(''method overriding'')とは継承による階層的クラス構造のインスタンスにおいて、サブクラスのメソッドシグネチャの処理内容でそのスーパークラス側の同じメソッドシグネチャの処理内容を置き換える仕組みを指す。メソッドシグネチャとは「返り値+メソッド名+引数欄」で構成される識別単位である。この指定は親側のメソッドが上書きされるのをデフォルトにするのと、子側のメソッドで上書きするのをデフォルトにする二通りがある。前者なら子側のメソッドを''override''や''redefine''で修飾しそれで親側メソッドを上書きする。後者なら親側のメソッドを''virtual''や''deferred''や''abstract''で修飾しそれは子側メソッドで上書きされる。それとは別にただメソッドを上書き不可にする場合は''final''などで修飾する。オーバーライドはメソッド名を参照アドレスにマッピングする[[仮想関数テーブル]]と呼ばれる機能を用いて実現される。 |
|||
;ドミナンス |
|||
:(''dominance'')は言語によってハイディング(''hiding'')マスキング(''masking'')とも呼ばれる。継承による階層的クラス構造において、サブクラスのメンバがスーパークラスの同名のメンバを隠していることを指す。親クラスのAメソッドを子クラスが同名Aメソッドでドミナンスした場合、子の型で参照してるインスタンスはそこでAのサーチが止まって子Aが呼び出される。ただし親の型で参照すれば親Aを呼び出せる。オーバーライドと異なり、参照する型でインスタンスの振る舞いを変えるための単純な仕組みでもある。 |
|||
;[[仮想継承]] |
|||
:(''virtual inheritance'')は、多重継承での[[菱形継承問題]]を回避するための仕組みである。菱形継承問題とは共にAクラスを親とするBクラスとCクラスの双方を継承した場合に、その継承構造上でAクラスが二つ重なって存在することになる不具合である。仮想継承では専用のテーブルが用意されて、そこでクラス名が参照アドレスにマッピングされる。BクラスからのAクラスと、CクラスからのAクラスは共に同じ参照アドレスをマッピングするのでAクラスはひとつにまとめられる事になる。同時に一度辿ったクラスは省略される事にもなる。 |
|||
;C3線形化 |
|||
:(''C3 linearization'')は、多重継承で用いられる幅優先のメソッド解決順序(''Method Resolution Order'')である。メソッドはクラスメンバと読み替えてもよい。自クラス内に無いメンバを探すための親クラスの順序を決定する仕組みである。一般の多重継承では、深さ優先検索によるメソッド解決順序が用いられて親クラスの重複は仮想継承で解決される。それに対してC3線形化では、深さレベルを先行基準にした親クラスの整列と重複した親クラスのマージが行われて、その結果の親クラス線形化リストは幅優先検索になる。 |
|||
;[[抽象クラス]] |
|||
:(''abstract class'')は、クラスメンバの一部のメソッドだけが抽象化されているクラスを意味する。抽象化されたメソッドとは、メソッドシグネチャ(返り値+メソッド名+引数欄)だけが定義されてコード内容が省略されているメソッドを意味する。抽象クラスはインスタンス化できないので継承専用になる。抽象メソッドは、サブクラスの方でメソッドのコード内容が実装されてオーバーライドされる。 |
|||
;[[インタフェース (抽象型)|インターフェース]] |
|||
:(''interface'')はプログラム概念と機能名の双方を指す用語である。言語によってはプロトコルと言われる。抽象メソッドと実メソッドをメンバにできる純粋抽象〜半抽象クラスを意味する。クラスの振る舞い側面を抜き出した抽象体である。クラスによるインターフェースの継承は実装と呼ばれる。多重実装可が普通である。ミックスインとの違いは、抽象階層に焦点が当てられている事であり、直下の実装オブジェクトを共通の振る舞い側面でまとめることがその役割である。インターフェースは自身の実装オブジェクトをグループ化できる。{{仮リンク|記名的型付け|en|Nominal type system|label=}}に準拠しているのでインターフェースの実装の明記が振る舞い側面の識別基準になる。インターフェースは抽象メソッド主体なので多重継承時のメンバ名の重複はあまり問題にならない。共通の実装メソッドに集約されるからである。インターフェースは非インスタンス対象である。 |
|||
;[[ミックスイン]] |
|||
:(''mixin'')はインターフェースに似たプログラム概念を指す用語である。機能名は言語によって[[トレイト]]、プロトコル、構造型(''structural type'')と言われる。抽象メソッドと実メソッドとデータメンバをメンバにできる継承専用クラスを意味する。クラスを特徴付けるための構成パーツである。クラスによるトレイトの継承は実装と呼ばれる。多重実装可が普通である。インターフェースとの違いは、トレイトの実装階層に焦点が当てられている事であり、オブジェクトを所有メンバで特定してまとめることがその役割である。トレイトは自身の[[上位集合]]であるオブジェクトをグループ化できる。{{仮リンク|構造的型付け|en|Structural type system|label=}}に準拠しているので所属メンバ構成自体がトレイト等価性の識別基準になる。これはトレイト実装を明記していなくても、そのトレイトが内包する全メンバを所持していれば同じトレイトと見なされることを意味する。トレイトは合成や交差が可能である。トレイトは多重継承時のメンバ名重複の際にその参照の優先順位に注意する必要がある。トレイトは非インスタンス対象である。 |
|||
;[[ダックタイピング]] |
|||
:''(duck typing'')は、特定のデータメンバ名またはメソッド名(メソッドシグネチャ)または識別子を持っているかどうかでインスタンスを分類すること。または選り分けること。選り分けられたインスタンスはその指名データメンバないし指名メソッドでのアクセス対象になる。動的型付けの機能であり、インスタンス、変数、オブジェクトを実行時に逐次判別するという点で型推論と区別されている。 |
|||
;[[型推論]] |
|||
:オブジェクト指向下の型推論''(type inference'')は、型宣言ないし型注釈を省略して定義された変数の「型」が自動的に導き出される機能を指す。型はクラスと同義である。静的型付けの機能であり、ソースコードを解析しながら値の代入を始めとしたその変数の扱われ方によって型を導き出す。ここで導き出される「型」とは他の変数への代入可能性や、関数の引数への適用可能性といったあくまで等価性の基準で決められるので、プログラマが人為的な意味付けによる型定義を重視している場合は予期せぬ結果が発生することにもなる。 |
|||
;[[メタクラス]] |
|||
:(''metaclass'')とはクラス自体の定義情報であり、そのクラスが持つとされるデータメンバ、メソッド、スーパークラス、内部クラスなどの定義が記録されたいわゆる[[メタデータ]]である。実装レベルでは、システム側が用意している特別なシングルトンオブジェクトと考えた方が分かりやすい。メタクラスの各種定義情報を参照または変更する機能はリフレクションと呼ばれる。メタクラスの変更はその対象クラスに直ちに反映される。クラスベースで用いられるものである。 |
|||
;[[リフレクション (情報工学)|リフレクション]] |
|||
:(''reflection'')は、メタクラスの定義情報を参照または変更する機能であるが、言語ごとに変更できる定義情報の範囲は異なっている。データメンバではデータ型、識別子、可視性が変更対象になる。メソッドではリターン型、識別子、パラメータリスト、可視性、仮想指定が変更対象になる。双方の追加定義と削除もできる事がある。スーパークラスも変更できる事がある。また、実行時の文字列(char配列やString)をデータメンバとメソッドの内部識別子として解釈できる機能もリフレクションに当たる。これは実行時の文字列によるデータメンバの参照とメソッドの呼び出しを可能にする。 |
|||
;[[アノテーション|メタアノテーション]] |
|||
:(''metadata annotation'')はクラスに任意の情報を埋め込める機能である。情報とは文字列と数値からなるキーワード、シンボル、テキストである。プログラマが自由な形式で書き込んで随時読み取るものであるが、システムから認識される形式のものもある。実装レベルではメタクラスに書き込まれてリフレクション機能またはその[[糖衣構文]]で読み取ることになる。[[マーカーインタフェース|マーカーインターフェース]]の拡張とも見なされている。メタアノテーションはクラス単位だけでなく、言語によってはインスタンス単位やメソッド単位でも埋め込むことができる。アドホック多相とされる。 |
|||
;動的ディスパッチ |
|||
:(''dynamic dispatch'')は、コンパイル時のメソッド名から呼び出されるメソッド内容が実行時に決定される仕組み全般を指す用語である。メソッドに引数を渡しての呼び出しを、オブジェクトにメッセージを発送(ディスパッチ)することになぞらえた事が由来である。発送先は実行時に選択決定されるメソッド内容を指す。メッセージは「this参照×第1引数×第2引数..」といった[[直積集合]]で考えられているのでシングル、[[ダブルディスパッチ|ダブル]]、[[多重ディスパッチ|マルチプル]]といった呼称になっている。発送先はthisおよび各引数の派生関係の組み合わせで選択される。thisの派生関係のみ影響しているのは仮想関数なシングルディスパッチである。それがthisでなく引数ならばただのシングルになる。thisと各引数の2個以上の派生関係が影響しているのはダブルないしマルチプルディスパッチになる。 |
|||
;[[動的束縛|動的バインディング]] |
|||
:(''dynamic binding'')は、識別子が参照するまたは呼び出すオブジェクト、インスタンス、メソッド、データメンバなどのプログラム要素が、コンパイル時ではなく実行時に決められる仕組み全般を指す用語である。識別子はいわゆる変数名や関数名などを指す。 |
|||
その実装としては[[オーバーライド|メソッドオーバーライド]]機能を活用した仮想関数と、実行時[[パターンマッチング]]機能を活用した総称関数の二つが挙げられる。{{仮リンク|仮想メソッド(OOP)|en|Virtual function|label=仮想関数}}はスーパークラスの抽象メソッドの呼び出しを、それを[[オーバーライド]]したサブクラスの実体メソッドの呼び出しにつなげるという動的ディスパッチ機能である。{{仮リンク|総称関数|en|generic function}}はオブジェクトの実行時[[パターンマッチング]]を使用する独立関数であり、その引数にされた各オブジェクトの型(=クラス)の組み合わせに従って実行コードブロックを選択決定するという[[多重ディスパッチ]]機能である。同名アルゴリズムを個々の派生クラスのメンバ関数に分散記述するのが仮想関数であり、個々の派生クラスの同名アルゴリズムを一つの独立関数に一括記述するのが総称関数である。 |
|||
;遅延バインディング |
|||
:(''late binding'')は、識別子が参照するオブジェクトをコンパイル時に決める事前バインディング(''early binding'')の対義語であり、この場合は識別子が参照するオブジェクトを実行時に決める動的バインディングと同じ意味で用いられる。また動的バインディングの中で、特に実行コードの動的ローディング機能を通して実装される方を遅延バインディングとする考え方もある。実行コードとは[[ダイナミックリンクライブラリ|DLL]]やクラスライブラリやモジュールなどを指しており、それらが内包するクラスやメソッドを専用の不透明型または動的束縛型に代入する。その呼び出しのための内部識別子はコンパイル時には存在していないことが多いので、実行時の文字列(char配列やString)を内部識別子に解釈するためのリフレクション機能が多用されることになる。 |
|||
=== コンポジションとデリゲーションとジェネリクス === |
|||
;[[パッケージ (Java)|パッケージ]] |
|||
{{仮リンク|オブジェクトコンポジション|en|Object composition|label=コンポジション (合成)}}と[[委譲|デリゲーション]](委譲)は、OOPでは[[継承 (プログラミング)|継承]]と対比される機能である。継承(特化)は[[Is-a]]関係の暗黙委譲、合成は[[Has-a]]関係の明示委譲と読み替えることができる。合成とは、特定処理の委譲先になる部品クラスの1個以上を持たせたクラス構造であり、そのクラスがとある処理を要求されてそれに対応できるデータ/メソッドを持っていない場合は、それに対応できる部品クラスを選択して処理を委譲するという仕組みである。その要求判別と選択過程を自動サーチ化したものが継承であり、部品クラスを基底クラスに置き換えて暗黙の委譲先にしたものである。しかしその自動サーチは、クラス階層に分散配置されているデータ/メソッドのどれが実際にアクセスされるのかという把握を困難にしたので、ここで差分プログラミング用途の継承の欠点が取り沙汰されるようになり、その後のクラスの機能拡張と分類体系化では、継承と合成の使い分けが重視されるようになった。また、[[Has-a]]関係はUML[[クラス図]]では合成(composition)と集約(aggregation)に分けられている。 |
|||
:(''package'')は1個以上のクラスをまとめたものである。多くなったクラスをグループ化するための仕組みである。パッケージの定義は言語ごとに異なるが、[[名前空間]](''namespace'')と同等の機能になっているケースが多い。実装レベルではパッケージ名は自動的にクラス名の接頭辞になってクラス名を差別化し、名前衝突を回避している。 |
|||
[[ジェネリックプログラミング|ジェネリクス]](総称化)は、オブジェクトの[[データ構造]]を汎用化して、それに汎用[[アルゴリズム]]の数々を適用できるようにした技術である。様々なデータ要素を内包するコンポジション(合成)オブジェクトは[[コンテナ (データ型)|コンテナ]](List/Set/Mapなど)と呼ばれ、その要素の型を型変数化することで汎用的な[[データ構造]]を表現し、その要素の型はコンテナのインスタンス化時に与えられる型パラメータによって決定される。ジェネリクスは[[データ構造]]と[[アルゴリズム]]を個別化しての柔軟な[[ソフトウェアコンポーネント|コンポーネント性]]を促進させ、[[イテレータ|反復子]]の方法論を確立した。また、[[圏論]]の[[圏 (圏論)|圏]]に見立てられた[[コンテナ (データ型)|コンテナ]]および[[対象 (圏論)|対象]]に見立てられたデータ要素の入れ子構造と、[[射 (圏論)|射]]に見立てられた[[派生型|サブタイピング]]の融合は、[[共変性と反変性 (計算機科学)|共変性と反変性]]の手法に発展した。 |
|||
;[[モジュール]] |
|||
:(''module'')は1個以上のクラスをまとめたものである。パッケージと似ているが、オブジェクト指向下のモジュールはもっぱら動的ローディング(遅延バインディング)と情報隠蔽に焦点を当てたプログラム概念である。情報隠蔽は[[カプセル化]]と同様に、自身の内包クラスの外部公開(輸出)と内部隠蔽を定義できる。自身が参照する他モジュールは輸入するという形式で明確に宣言される。動的ローディング用途のモジュールでは内包する基底クラスの詳細を明らかにしつつも、その派生クラスの種類と詳細を明らかにしていないケースが多々あるので、その派生クラスを代入するための動的束縛型は特に不透明型(''opaque type'')と呼ばれる。不透明型はもっぱら型制約と併せて用いられる。 |
|||
;[[モンキーパッチ]] |
|||
:(''monkey patch'')はモジュールやスクリプトファイルなどの動的ローディングを用いて、インタプリタ実行後またはコンパイル後のソースコード内容を変化させる手法である。ソースコードに特定のフィルター処理を記述しておき、その中で任意の箇所を動的ローディングされたモジュール内のクラスや関数や変数で置き換えさせる事で、その時の配置モジュールに合わせた処理内容の変化ができる。モジュールを外せばフィルター処理は無効になる。この置き換え(パッチ当て)は遅延バインディング相当である。ソースコードを変えなくてよいのが条件である。 |
|||
;[[ジェネリクス]] |
|||
:(''generics'')は、クラス内のデータメンバの型とメソッドの引数および返り値の型を総称化して型変数とし、コンストラクタの型引数に任意のクラスを適用してインスタンスを生成する仕組みを指す。型変数はその適用クラスで置き換えられる。クラス内の型の決定をコンストラクタまで先送りする手法であり、それはジェネリッククラスと呼ばれる。型変数をバリアンスにしたジェネリッククラスは、適用クラス値とその派生クラス値を同等に扱うことができる。型変数のバリアンスを用いないジェネリクスの方は特にテンプレートと呼ばれる。パラメトリック多相とされる。 |
|||
;[[テンプレート (プログラミング)|テンプレート]] |
|||
:(''template'')は型変数のバリアンスを用いない方のジェネリクスを指す。コンパイル時にテンプレートクラスの型変数(仮型引数)部分に、そのコンストラクタコールそれぞれの型引数(実型引数)を当てはめたソースコードがそのまま複製される仕組みである。パラメトリック多相とされる。 |
|||
;[[共変性と反変性 (計算機科学)|バリアンス]] |
|||
:(''variance'')は、ある型で注釈された値に、その型の派生型または基底型の値も適用できるようにする仕組みである。その型の派生型の値も適用できるようにするのは共変性と呼ばれる。その型の基底型の値も適用できるようにするのは反変性と呼ばれる。バリアンスは一つの値を軸にした基底関係と派生関係の双方を包括する用語であるが、オブジェクト指向ではもっぱらジェネリクスのカテゴリで用いられており、ジェネリッククラスの型変数が対象にされている。ジェネリッククラスが扱う値の幅を持たせる機能である。共変クラスは適用クラス値とその派生クラス値を同等に扱うことができる。反変クラスは適用クラス値とその基底クラス値を同等に扱うことができる。バリアンスはジェネリッククラスの継承構造上で様々に応用される。 |
|||
;型制約 |
|||
:(''type constraint'')は、ジェネリッククラスの型引数ないし型変数、代入値の型が実行時に決められる動的束縛型の変数、動的ローディング時に詳細が隠されたままの値が代入される不透明型の変数などの宣言に用いられるものである。それぞれは制約用の基準クラスで記号修飾され、その基準クラスの派生型の値が代入、束縛、適用されるという宣言になる。型引数と型変数では基準クラスの派生クラスが適用される宣言になる。動的束縛型では基準クラスの派生型の値が代入される宣言になる。不透明型では基準クラスの詳細不明な派生型の値が代入される宣言になる。これらは共変性に基づいている。それに対して反変性に基づいた型制約もあり、上述の説明内の’’派生’’を’’基底’’に置き換えたものになる。型制約は型境界(''type bound'')とも呼ばれる。 |
|||
;タイプメンバ |
|||
:(''abstract type member'')はジェネリッククラスのメンバ要素であり、ジェネリッククラス同士で型変数の内容をやり取りするための仲介要素である。Aクラスコンストラクタの型引数にBクラスを適用した際に、適切な代入定義が併記されたAクラス内のタイプメンバに、Bクラスがその内部で扱っている総称型もセットで適用できる。連想配列さながらにBクラスがキー的存在になってAクラスのタイプメンバ内容も決定されることから、この仕組みは関連型(''associated type'')と呼ばれる。 |
|||
;[[関数オブジェクト]] |
|||
:オブジェクト指向下の関数オブジェクト(''function object'')は、メソッドそのものをオブジェクトして扱うというプログラム概念である。関数型プログラミングの[[クロージャ]]をモデルにしている。単にインスタンスを関数名らしく見せるための糖衣構文である( )[[演算子オーバーロード]]や、メソッドシグネチャを型種にした[[関数ポインタ]]型の変数である[[デリゲート (プログラミング)|デリゲート]]などの実装形式がある。デリゲート変数にはインスタンスメソッドへの参照が代入されてクラス種類とそのインスタンス種類による処理の多相を表現できる。プロトタイプベースにおける関数はオブジェクトそのものと言える存在であり、ローカル変数がプロパティ存在になっているのでクロージャが自然表現できる他、引数構成もプロパティ存在になっている場合はそれも変更できてクラスベースにおけるリフレクションを自然表現する。 |
|||
;[[コルーチン]] |
|||
:オブジェクト指向下の[[イテレータ]]、[[ジェネレータ (プログラミング)|ジェネレータ]]、デコレータは、コルーチン(''coroutine'')機構に基づいている。通常のサブルーチンがコールする側の復帰アドレスだけをスタックに積むのに対して、コルーチンはコールする側とコールされる側双方の復帰アドレスをスタックに積むというサブルーチン機構である。各要素への作用が記されたオペレータが[[無名関数]]やラムダ式などの形態で[[コンテナ (データ型)|データコンテナ]]に渡されると、各要素をフェッチするデータコンテナと、フェッチされた要素を参照ないし加工するオペレータが交互に[[コールスタック]]を用いて連携動作を繰り返す。イテレータはオペレータをそのまま扱う機能である。ジェネレータはオペレータが反復処理を終えた後にその総和値や選別リストを生成する機能である。デコレータはメソッドをデータコンテナと見なしそのメソッド内での関数コールをそれぞれ要素にして、オペレータがフェッチされた関数名と引数欄を見ながら任意の処理を挿入する機能である。 |
|||
;[[メッセージ転送|メッセージレシーバー]] |
|||
:(''message receiver'')はメッセージを受け取ることに特化されたメソッドである。メッセージレシーバーはインスタンスのデフォルトで呼び出される窓口レシーバーの形態と、指定メソッドが存在していない時に呼び出される補足レシーバーの形態がある。窓口レシーバーのメッセージはセレクタと引数のペアまたはそのどちらかだけという書式である。窓口レシーバーは極めて柔軟なプロセスを実現できるが、実装の煩雑さとオーバーヘッドが大きくなる。セレクタは識別子またはペア引数の注釈になる文字列である。セレクタはメソッドへの自動分岐が主な用途になるが、そのフィルター処理と取りこぼし処理の中でただのキーワードとしても自由に解釈できる。補足レシーバーのメッセージはメソッド名文字列と引数配列という書式になっており、いかなるメソッドシグネチャにも該当しなかった取りこぼしになる。このメソッド名文字列と引数配列を自由に解釈して柔軟な処理を行える。補足レシーバーの機能名はメソッドミッシングなどである。 |
|||
;[[派生型|サブタイピング]] |
|||
:(''subtyping'')はクラス(型)のあらゆる派生関係および派生構造の実装形式とその働き方を包括したプログラム概念である。サブタイプ多相(''subtype polymorphism'')とも呼ばれる。継承、オーバーライド、コンポジション、ジェネリクス、共変バリアンス、引数バリアンスによるディスパッチ、不透明型といったものは全てサブタイピングの一側面である。オブジェクト指向でよく使われるものは振る舞いサブタイピング(''behavioral subtyping'')であり、これに当てはまるものは継承とメソッドのオーバーライドを組み合わせた仮想関数である。 |
|||
=== 動的ディスパッチとメッセージパッシング === |
|||
;[[委譲|デリゲーション]] |
|||
{{仮リンク|動的ディスパッチ|en|Dynamic dispatch}}は、OOPの[[ポリモーフィズム]]の原型機能であり、コンパイル時に確定されたメソッド名から呼び出されるメソッド内容(実行コードブロック)が、実行時に選択決定(ディスパッチ)される仕組み全般を指している。メソッドに与えられた各引数の型の組み合わせに従って、実行コードブロックが選択決定される仕組みのシングルディスパッチと[[多重ディスパッチ]]を包括している。先頭引数の型[[パターンマッチング]]固定でディスパッチされるのはシングルになり、そうでないならば多重になる。例えば[[仮想関数]]は[[This (プログラミング)|This]]のシングルディスパッチである。 |
|||
:委譲(''delegation'')。呼び出されたあるクラスのメソッドが自分への引数を他のクラスの同名メソッドにそのまま渡して、その同名メソッドからの返り値をそのまま呼び出し元に渡すという仕組みを指す。委譲先のクラスはhas-a関係で保有されているものになる。委譲先メソッドは必ずしも同名ではなくマッピング名の場合もあり、引数も構成を変えて渡される場合もある。 |
|||
メッセージパッシングでは引数の型に加えて、メソッド名も実行時に解釈される要素にされており、そこでただのシンボルとして扱われるメソッド名はセレクタと呼ばれている。セレクタはメッセージ式を基本文とするSmalltalk様式のOOPで用いられる。<code>object selector: param</code>ような書式でオブジェクトの共通窓口になるメッセージレシーバーに、セレクタと引数値で構成されたメッセージが送られる。また、<code>object.call(method_name, param)</code>のような書式でオブジェクトの共通窓口関数をコールするのもメッセージパッシングと呼ばれる。これは[[Remote Procedure Call|RPC]]や[[Object Request Broker|ORB]]などの分散オブジェクト技術で用いられている。メソッド名(関数名)も実行時に解釈されるという特徴を指してメッセージパッシングと呼ぶ。メッセージレシーバーでは、渡されたセレクタの[[パターンマッチング]]に従って実行コードブロックがディスパッチされることが多く、OOP原点のSmalltalkは、引数と[[This (プログラミング)|This]]が与えられるその実行コードブロックをメソッドと呼んでいた。 |
|||
;フォワーディング |
|||
:転送(''forwarding'')。委譲先のクラスのメソッドが処理を行わずに、そのまた他のクラスの同名メソッドに引数をそのまま渡して、その返り値をそのまま呼び出し元に渡している場合、冒頭の委譲は転送になる。転送用メソッドではどのクラスに引数をパスするかという選択が行われるので、デリゲーションの多相を表現できる。 |
|||
=== インターフェースとトレイト === |
|||
;汎化 |
|||
[[インタフェース (抽象型)|インターフェース]]は、[[カプセル化]]と[[継承 (プログラミング)|継承]]の[[派生型|サブタイピング]]用法を促進した機能である。情報隠蔽とデータ抽象とメソッド抽象を合わせて表現する。[[クラス (コンピュータ)|クラス]]から見たインターフェースは自身のサービスのモデル化である。OOPの[[インタフェース (抽象型)|インターフェース]]は基本的には抽象メソッドのみで構成される[[抽象型]]と定義されている。その実装方式は純粋抽象クラスが基本形にされており、インスタンス化はできない継承専用クラスになって多重継承が前提にされている。インターフェースの抽象メソッドは、その実装クラスの同名具象メソッドで[[オーバーライド]]される。インターフェースの各抽象メソッドはセッター・ゲッター・プロセスとして動作し、その実装内容は隠蔽されて実行時ごとに決定される。その代表使用例は[[ソフトウェアコンポーネント]]間の相互通信媒体である。 |
|||
:(''generalization'')は継承による[[is-a]]関係であり、サブクラスからスーパークラスへの連結を指す。 |
|||
;特化 |
|||
:(''specialization'')は継承による[[is-a]]関係であり、スーパークラスからサブクラスへの連結を指す。 |
|||
;実現 |
|||
:(''realization'')はクラスの振る舞いの抽象化による[[is-a]]関係であり、クラスからインターフェースへの連結を指す。振る舞いとは特定の目的に沿ったメソッド群である。 |
|||
;実装 |
|||
:(''implementation'')はクラスの振る舞いの抽象化による[[is-a]]関係であり、インターフェースからクラスへの連結を指す。振る舞いとは特定の目的に沿ったメソッド群である。 |
|||
;合成 |
|||
:(''composition'')は強い[[has-a]]関係。AクラスがBクラスをデータメンバにし、Aのコンストラクタと同時にBインスタンスが生成され、Aのデストラクタと同時にBインスタンスが破棄される場合、AはBの合成となる。Bが自身のサブクラスで交換される場合は分離とともに破棄される。 |
|||
;集約 |
|||
:(''aggregation'')は弱い[[has-a]]関係。AクラスがBクラスをデータメンバにし、Aクラスのコンストラクタとは関係なくBインスタンスが生成され、AクラスのデストラクタでBインスタンスが破棄されず、また分離時も破棄されない場合、AはBの集約となる。Aクラスがコレクション(配列、List、Set、Map)の仕組みでBインスタンスを持つ場合も、AはBの集約となる。コレクション性を強調する場合は収容(''containment'')とすることもある。 |
|||
;関連 |
|||
:(''association'')。AクラスがBクラスのメソッドを呼び出す場合、AはBに関連しているとなる。AはBへの誘導可能性を持つとされる(A→B)。has-a関係で保有しているインスタンスのメソッドを呼び出すという意味で関連線は合成線または集約線と重ねて引かれることが多い。 |
|||
;依存 |
|||
:(''dependency'')。AクラスのメソッドがBクラスのインスタンスを引数または返り値にしている場合、AはBに依存しているとなる。返り値の例として、Aのメソッドがその返り値としてBインスタンスを生成する場合も、AはBに依存しているとなる。 |
|||
;SOLID |
|||
:(''SOLID Principles'')は、汎化・特化・実現・実装・関連・依存の連結線に焦点を当てたクラスの設計原則である。(S)単一責任原則・(O)解放閉鎖原則・(L)リスコフの置換原則・(I)インターフェース分離原則・(D)依存の逆向き原則といった五つから成り立っている。1974年にバーバラ・リスコフが提唱した(L)と、1988年にバートランド・メイヤーが提唱した(O)に、ロバート・マーティンが(S)(I)(D)を加えて2000年に発表されている。これはSOLIDの文字通りの順に解釈できるようになっている。 |
|||
:(S)単一責任原則は、クラス(属性・操作)はただ一つの機能を表現するようにデザインすることを推奨している。(O)解放閉鎖原則は、クラスを抽象クラス(汎化・実現)と実装クラス(特化・実装)に分けてデザインすることを推奨している。(L)リスコフの置換原則は、汎化と特化に対する枠組みであり、実装クラスはその抽象クラスに対して振る舞い(=仮想関数)的に等価計算が可能であることを推奨している。(I)インターフェース分離原則は、実現と実装に対する枠組みであり、一つの抽象クラスは互いにその動作内容に影響し合うメソッドたちのみで構成されることを推奨している。(D)依存の逆向き原則は、関連と依存に対する枠組みであり、AクラスからBクラスに向けて関連線を引きたい場合は、Bクラスからその抽象クラスをAクラスに向けて実現し、その抽象クラスに対してAクラスからの関連線を引くことを推奨している。Bクラスとその抽象クラスを結ぶ依存線が、Aクラスからの関連線と逆向きになることがその名の由来である。 |
|||
OOP原点の[[Smalltalk]]処理系由来の[[トレイト]]は、[[クラス (コンピュータ)|クラス]]への機能注入を目的にした[[メソッド (計算機科学)|メソッド]]の集合体であり、トレイトの多重継承を扱う作法は[[ミックスイン]]と呼ばれている。トレイトの継承はインクルードともされ、これはUML[[クラス図]]の”特化”と”実装”ではない第三の継承概念になるので、従来の標準OOP路線からは外れていた。後の[[依存性逆転の原則]]および[[依存性の注入]]の[[デザインパターン (ソフトウェア)|デザインパターン]]では、[[Mixin|Mix-in]]の作法が注目され、そこでの[[トレイト]]の役割を与えた[[インタフェース (抽象型)|インターフェース]]の応用設計が扱われている。そのMix-inをUML[[クラス図]]は、特定の機能([[サーバー]]や[[データベース]]など)から”実現”されたインターフェース(依存対象)に向けてオブジェクトが”関連”するという図式にしている。この手法は分散オブジェクト技術の後継としてのDIコンテナで用いられている。 |
|||
; GOFデザインパターン |
|||
: 生成に関するパターン<gallery heights="40"> |
|||
<!-- 以下、[[en:Object-oriented programming]] oldid=1047374345 の翻訳 -->== デザインパターン一覧 == |
|||
=== 継承と振る舞いサブタイピング === |
|||
[[継承 (プログラミング)|継承]]が[[Is-a]]関係を表現して、[[サブクラス (計算機科学)|サブクラス]]の[[インスタンス]]は[[スーパークラス (計算機科学)|スーパークラス]]の[[インスタンス]]を安全に置換できるという直感は、多くのOOP言語には当てはまっておらず、ミュータブルな[[オブジェクト (プログラミング)|オブジェクト]]を扱っていても同様である。型チェック機構付きのサブタイプ多相は、{{仮リンク|振る舞いサブタイピング|en|Behavioral subtyping}}の正当性までを保証しない。一般的に振る舞いサブタイピングは[[非決定性チューリングマシン|非決定性]]なので、そのための言語機能の実装は非現実的であり、[[クラス (コンピュータ)|クラス]]またはオブジェクトの継承関係の設計は、プログラマの手によって注意深く行われる必要がある。スーパークラスとサブクラス間の理想的な振る舞いサブタイピングを実現するためのデザインパターンとしてよく知られているのが、[[リスコフの置換原則]]である。 |
|||
=== GOFデザインパターン === |
|||
1994年に”[[Gang of Four]]”がその著作で発表した23のデザインパターンは、余りに有名である。 |
|||
: 生成のパターン<gallery heights="30" perrow="6"> |
|||
ファイル:Abstract Factory UML class diagram.svg|[[Abstract Factory パターン|Abstract factory]] |
ファイル:Abstract Factory UML class diagram.svg|[[Abstract Factory パターン|Abstract factory]] |
||
ファイル:Factory Method UML class diagram.svg|[[Factory Method パターン|Factory Method]] |
|||
ファイル:Builder UML class diagram.svg|[[Builder パターン|Builder]] |
ファイル:Builder UML class diagram.svg|[[Builder パターン|Builder]] |
||
ファイル:Factory Method UML class diagram.svg|[[Factory Method パターン|Factory Method]] |
|||
ファイル:Prototype UML.svg|[[Prototype パターン|Prototype]] |
ファイル:Prototype UML.svg|[[Prototype パターン|Prototype]] |
||
ファイル:Singleton UML class diagram.svg|[[Singleton パターン|Singleton]] |
ファイル:Singleton UML class diagram.svg|[[Singleton パターン|Singleton]] |
||
</gallery> |
</gallery> |
||
: 構造 |
: 構造のパターン<gallery heights="30" perrow="8"> |
||
ファイル:Adapter pattern UML diagram.PNG|[[Adapter パターン|Adapter]] |
ファイル:Adapter pattern UML diagram.PNG|[[Adapter パターン|Adapter]] |
||
ファイル:Bridge UML class diagram.svg|[[Bridge パターン|Bridge]] |
ファイル:Bridge UML class diagram.svg|[[Bridge パターン|Bridge]] |
||
224行目: | 249行目: | ||
ファイル:UML DP Proxy.png|[[Proxy パターン|Proxy]] |
ファイル:UML DP Proxy.png|[[Proxy パターン|Proxy]] |
||
</gallery> |
</gallery> |
||
: 振る舞い |
: 振る舞いのパターン<gallery heights="30" perrow="12"> |
||
ファイル:Chain of responsibility UML diagram.png|[[Chain of Responsibility パターン|Chain of Responsibility]] |
ファイル:Chain of responsibility UML diagram.png|[[Chain of Responsibility パターン|Chain of Responsibility]] |
||
ファイル:Command Design Pattern Class Diagram.png|[[Command パターン|Command]] |
ファイル:Command Design Pattern Class Diagram.png|[[Command パターン|Command]] |
||
231行目: | 256行目: | ||
ファイル:Mediator design pattern.png|[[Mediator パターン|Mediator]] |
ファイル:Mediator design pattern.png|[[Mediator パターン|Mediator]] |
||
ファイル:Memento design pattern.png|[[Memento パターン|Memento]] |
ファイル:Memento design pattern.png|[[Memento パターン|Memento]] |
||
ファイル:Observer UML smal.png|[[Observer パターン|Observer]] |
ファイル:Observer UML smal.png|[[Observer パターン|Observer]] |
||
ファイル:State Design Pattern UML Class Diagram.svg|[[State パターン|State]] |
ファイル:State Design Pattern UML Class Diagram.svg|[[State パターン|State]] |
||
ファイル: |
ファイル:Strategy Pattern in UML.png|[[Strategy パターン|Strategy]] |
||
ファイル:Template Method UML class diagram.svg|[[Template Method パターン|Template Method]] |
ファイル:Template Method UML class diagram.svg|[[Template Method パターン|Template Method]] |
||
ファイル:Visitor UML class diagram.svg|[[Visitor パターン|Visitor]] |
ファイル:Visitor UML class diagram.svg|[[Visitor パターン|Visitor]] |
||
</gallery> |
</gallery> |
||
=== 責任駆動設計とデータ駆動設計 === |
|||
OOPで提唱された責任駆動設計(RDD)とは、特定の機能を実現する責任およびその機能が共有する情報に基づいて、[[クラス (コンピュータ)|クラス]]を定義していくデザインパターンである。責任駆動設計では、振る舞い抽象としてのクラスに焦点を当てており、必然的に[[インタフェース (抽象型)|インターフェース]]や[[抽象クラス]]が多用されることになる。 |
|||
OOPにおけるデータ駆動設計とは、保持する[[データ構造]]に基づいて、クラスを定義していくデザインパターンである。データ駆動設計では、データ抽象としてのクラスに焦点を当てており、[[カプセル化]]と[[抽象データ型]]の概念に重きが置かれる。{{仮リンク|レベッカ・ウーフ‐ブロック|en|Rebecca Wirfs-Brock}}によって彼女の責任駆動設計と、従来のデータ駆動設計は対比されるようになっている。 |
|||
===SOLID、GRASPのガイドライン=== |
|||
[[SOLID]]のガイドラインは、プログラミングにおける五つの実践の頭文字をとった語呂合わせであり、マイケル・C・フェザーズ<ref>https://wiki.c2.com/?MichaelFeathers</ref>が考案し提唱したものである |
|||
* '''S''':[[:en:Single responsibility principle|単一責任の原則(英語版)]] |
|||
* '''O''':[[開放/閉鎖原則]] |
|||
* '''L''':[[リスコフの置換原則]] |
|||
* '''I''':[[:en:Interface segregation principle|インターフェイス分離の原則(英語版)]] |
|||
* '''D''':[[依存性逆転の原則]] |
|||
[[GRASP]](General Responsibility Assignment Software Patterns)は、[[:en:Craig Larman|クレーグ・ラーマン]]が提唱したもう一つガイドラインである。 |
|||
<!-- 以上、[[en:Object-oriented programming]] oldid=1047374345 の翻訳 --> |
|||
== 公式意味論 == |
|||
数々の識者によってOOPで扱われる概念を公式化する試みが行われている。OOP概念の解釈に用いられる代表的なコンセプトは以下の通りである。 |
|||
* [[F余代数|''F''余代数]](''F''-coalgebra) |
|||
* [[抽象データ型]](abstract data type) - {{仮リンク|存在型|en|Type_system#Existential_types}}を含む。なお、動的ディスパッチはサポートしていない。 |
|||
* [[再帰データ型]](recursive type) |
|||
* [[カプセル化|カプセル化状態]](encapsulated state) |
|||
* [[継承 (プログラミング)|継承]](inheritance) |
|||
* [[レコード (計算機科学)|レコード]](record)- 関数リテラルを持つレコードがオブジェクトと見なされるが、本格的なOOPになるにはそれ以上の複雑さが必要である。 |
|||
”オブジェクト”の共通認識的な定義または理論を見つけようとする試みはそれほど成功していない。{{仮リンク|ルカ・カーデリ|en|Luca Cardelli}}らによる[http://portal.acm.org/citation.cfm?id=547964&dl=ACM&coll=portal ''A Theory of Objects'']<ref name="AbadiCardelli">{{Cite book|和書|first=Martin|last=Abadi|title=A Theory of Objects|url=http://portal.acm.org/citation.cfm?id=547964&dl=ACM&coll=portal|year=1996|isbn=978-0-387-94775-4|publisher=Springer-Verlag New York, Inc.|author-link=Martin Abadi|author2=Cardelli, Luca}}</ref>は、比較的成功している例とされる。 |
|||
== オブジェクト指向言語一覧 == |
|||
ここではクラスベースの記述は省略している。 |
|||
<div style="{{column-count|2}}"> |
|||
* [[Simula|Simula67]] 1967年 静的 |
|||
* [[Smalltalk]] 1972年 動的・メッセージ式・純粋系 |
|||
* [[C++]] 1983年 静的 |
|||
* [[Objective-C]] 1984年 静的と動的・メッセージ式 |
|||
* [[Object Pascal]] 1986年 静的 |
|||
* [[Eiffel]] 1986年 静的・純粋系 |
|||
* [[Self]] 1987年 動的・プロトタイプベース・メッセージ式・純粋系 |
|||
* [[Modula-3]] 1988年 静的 |
|||
* [[Common Lisp]]([[CLOS]]) 1988年(ANSI規格化は1994年) 動的・多重ディスパッチ・[[The Art of the Metaobject Protocol|メタオブジェクト]] |
|||
<!-- :[[クラスベース]]のオブジェクト指向。メソッド記述の関数呼び出し形式への統合、[[多重ディスパッチ]]、クラスの動的な再定義等を特徴とする。--> |
|||
*[[Oberon-2]] 1991年 静的 |
|||
*[[Dylan]] 1992年 動的・多重ディスパッチ |
|||
*[[Lua]] 1993年 動的・プロトタイプベース |
|||
* [[Python]] 1994年(ver1.0) 動的 |
|||
* [[Delphi]] 1995年 静的 |
|||
*[[Ada]] 1995年からOOP化 静的 |
|||
*[[Perl]] 1995年からOOP化 動的 |
|||
* [[Ruby]] 1995年 動的・純粋系 |
|||
*[[Java]] 1996年(ver1.0) 静的 |
|||
* [[JavaScript]] 1996年(first released) 動的・プロトタイプベース |
|||
*[[OCaml]] 1996年 静的・関数型 |
|||
*[[Squeak]] 1996年 動的・メッセージ式 |
|||
*[[ECMAScript]] 1997年 動的・プロトタイプベース |
|||
*[[C Sharp|C#]] 2000年 静的と動的 |
|||
*[[Visual Basic .NET|Visual Basic.NET]] 2001年 静的 |
|||
*[[D言語]] 2001年 静的 |
|||
*[[Io (プログラミング言語)|Io]] 2002年 動的・プロトタイプベース・メッセージ式・純粋系 |
|||
*[[COBOL]] 2002年からOOP化 静的 |
|||
*[[FORTRAN]] 2003年からOOP化 静的 |
|||
*[[R言語]] 2003年からOOP化 動的・関数型・多重ディスパッチ |
|||
* [[Scala]] 2003年 静的・関数型 |
|||
*[[Groovy]] 2003年 動的 |
|||
*[[PHP (プログラミング言語)|PHP]] 2004年からOOP化 静的と動的 |
|||
*[[F Sharp|F#]] 2005年 静的・関数型 |
|||
*[[MATLAB]] 2008年からOOP化 動的・関数型 |
|||
*[[Go (プログラミング言語)|Go]] 2009年 静的 |
|||
*[[Rust (プログラミング言語)|Rust]] 2010年 静的・関数型 |
|||
* [[Kotlin]] 2011年 静的 |
|||
*[[Ceylon]] 2011年 静的 |
|||
*[[Dart]] 2011年 静的・関数型 |
|||
*[[Elixir (プログラミング言語)|Elixir]] 2011年 動的・関数型 |
|||
*[[Julia (プログラミング言語)|Julia]] 2012年 動的・関数型・多重ディスパッチ |
|||
* [[TypeScript]] 2012年 静的と動的・関数型 |
|||
*[[Swift (プログラミング言語)|Swift]] 2014年 静的・プロトコル指向 |
|||
*[[Raku]] 2015年 静的と動的 |
|||
</div> |
|||
== 用語一覧 == |
|||
ここでは日本語ページ化されている項目のみ列挙している。 |
|||
<div style="{{column-count|3}}"> |
|||
* [[クラスベース]] |
|||
*[[プロトタイプベース]] |
|||
*[[メッセージ (コンピュータ)|メッセージ]] |
|||
*[[クラス (コンピュータ)|クラス]] |
|||
*[[インスタンス]] |
|||
*[[フィールド (計算機科学)|フィールド]] |
|||
*[[プロパティ (プログラミング)|プロパティ]] |
|||
*[[メソッド (計算機科学)|メソッド]] |
|||
* [[インスタンス変数]] |
|||
* [[クラス変数]] |
|||
*[[コンストラクタ]] |
|||
*[[デストラクタ]] |
|||
*[[カプセル化]] |
|||
* [[継承 (プログラミング)|継承]] |
|||
*[[ポリモーフィズム|多態性]] |
|||
*[[This (プログラミング)|This]] |
|||
* [[Is-a]] |
|||
* [[Has-a]] |
|||
*[[派生型|サブタイピング]] |
|||
*[[ダックタイピング]] |
|||
*[[ミックスイン]] |
|||
*[[スーパークラス (計算機科学)|スーパークラス]] |
|||
*[[サブクラス (計算機科学)|サブクラス]] |
|||
*[[抽象クラス]] |
|||
*[[メタクラス]] |
|||
*[[オーバーライド]] |
|||
*[[仮想関数テーブル]] |
|||
*[[菱形継承問題]] |
|||
*[[仮想継承]] |
|||
*[[インタフェース (抽象型)|インターフェース]] |
|||
*[[トレイト]] |
|||
* [[抽象型]] |
|||
*[[オブジェクト型]] |
|||
*[[型クラス]] |
|||
*[[委譲]] |
|||
*[[多重ディスパッチ]] |
|||
*[[ダブルディスパッチ]] |
|||
*[[多重定義|オーバーロード]] |
|||
*[[アノテーション]] |
|||
*[[コンテナ (データ型)|コンテナ]] |
|||
*[[ボックス化]] |
|||
*[[ジェネリクス]] |
|||
*[[共変性と反変性 (計算機科学)|共変性と反変性]] |
|||
*[[モジュール]] |
|||
*[[ソフトウェアコンポーネント]] |
|||
*[[リフレクション (計算機科学)|リフレクション]] |
|||
*[[モンキーパッチ]] |
|||
*[[メッセージ転送]] |
|||
*[[イミュータブル]] |
|||
*[[型システム]] |
|||
*[[オブジェクト指向分析設計]] |
|||
*[[オブジェクト指向モデリング]] |
|||
*[[統一モデリング言語|UML]] |
|||
*[[契約による設計]] |
|||
*[[デザインパターン (ソフトウェア)|GOFデザインパターン]] |
|||
*[[リファクタリング (プログラミング)|リファクタリング]] |
|||
*[[依存性の注入]] |
|||
</div> |
|||
== 脚注 == |
== 脚注 == |
||
243行目: | 408行目: | ||
== 関連項目 == |
== 関連項目 == |
||
{{Wikibooks|オブジェクト指向|オブジェクト指向}} |
|||
{{Normdaten}} |
{{Normdaten}} |
||
{{プログラミング言語の関連項目}} |
{{プログラミング言語の関連項目}} |
||
{{デフォルトソート:おふしえくとしこうふろくらみんく}} |
{{デフォルトソート:おふしえくとしこうふろくらみんく}} |
||
[[Category:オブジェクト指向|*ふろくらみんく]] |
[[Category:オブジェクト指向|*ふろくらみんく]] |
2021年10月23日 (土) 12:14時点における版
プログラミング・パラダイム |
---|
オブジェクト指向プログラミング(オブジェクトしこうプログラミング、英: object-oriented programming、略語:OOP)とは「オブジェクト」という概念に基づいたプログラミングパラダイムの一つである。 オブジェクトは、任意個数のフィールド (属性、プロパティまたは変数)で構成されるデータと、任意個数の(メソッドまたは関数)で構成されるコードのひとまとまりで構成される。
オブジェクトの特徴として、オブジェクト自身の手続きが自身のデータフィールドを読み書きできることが挙げられる(オブジェクトにはthis
やself
という概念がある)。また、OOPでは、相互に作用するオブジェクトを組み合わせてプログラムを設計する[1][2]。OOP言語のありかたは多様であるが、最も一般的といえるものは、オブジェクトがクラスのインスタンスであり、また、オブジェクトの型もクラスとして規定されるクラスベースといわれるものである。
広く使われているプログラミング言語の多く(C++、Java、Pythonなど)は、マルチパラダイムであるが、程度の差はあれ、オブジェクト指向プログラミングをサポートしており、大抵は命令型や手続き型プログラミングとの組み合わせで用いられる。 主なオブジェクト指向言語には次のようなものが挙げられる: Java、C++、C#、Python、R、PHP、Visual_Basic_.NET、JavaScript、Ruby、Perl、SIMSCRIPT(英語版)、Object Pascal、Objective-C、Dart、Swift、Scala、Kotlin、Common Lisp、MATLAB、そしてSmalltalk。
歴史
現在のオブジェクト指向プログラミングという文脈における「オブジェクト」や「指向」を表す用語が初めて登場したのは、1950年代後半から1960年代前半にかけてのマサチューセッツ工科大学(MIT)においてである。 1960年代初頭の人工知能グループ界隈では、「オブジェクト」はプロパティ(属性)を持つ個体識別可能なアイテム(LISPのatom)を意味していた[3][4]。 後にアラン・ケイは、1966年にLISPの内部構造を詳細に理解したことが彼の考え方に強い影響を与えたと述べている。[5]
MITにおける初期の例としては、この他にも、1960年から1961年にかけてアイバン・サザランドが作成したSketchpadが挙げられる。サザランドは、1963年の技術レポートの用語集(Sketchpadに関する自身の博士論文をもとにしたもの)で、グラフィカルなインタラクションに特化しているとはいえ「オブジェクト」と「インスタンス」の概念を定義している(クラスの概念は"master"または"definition"として把握されている)。[6] また、MIT版のALGOLであるAED-0では、データ構造(この言語の方言では"plexes"と呼称)と手続きを直接結びつけ、後に「メッセージ」、「メソッド」、「メンバ関数」と呼ばれるようなものの萌芽がみられる。[7][8]
1962年、クリステン・ニゴールはノルウェー計算センターでシミュレーション言語のプロジェクトを開始した。これは彼が以前に用いたモンテカルロ法と実世界のシステムを概念化する仕事に基づくものであった。オーレ=ヨハン・ダールが正式にプロジェクトに参加し、UNIVAC I(UNIVAC 1107)上で動作するSimulaプログラミング言語が設計された。Simulaは、クラスやオブジェクト、継承、ダイナミックバインディングなど、今日のオブジェクト指向プログラミングには不可欠である重要な概念を導入した。[9]
Simulaはまた、プログラミングにおけるデータ保全を考慮して設計されたものでもあった。プログラミングのデータ保全のために参照カウントによる検出プロセスが実装されたのに加え、最終手段としてガベージコレクタがメモリ内の使用されていないオブジェクトを削除するようになっていた。しかし、データオブジェクトの概念は1965年には既に確立されていたものの、プライベート(-)やパブリック(+)といった変数のスコープのレベルによるデータのカプセル化については、アクセスする手続きもまた隠蔽できなければならなかったため、Simulaでは実装されなかった。[10]
初期の段階では、Simulaはプログラミング言語ALGOL 60のための手続きパッケージとされていた。しかし、ALGOLによる制約に不満を感じた研究者たちは、UNIVAC ALGOL 60コンパイラを使用した本格的なプログラミング言語としてSimulaを開発することにした。ダールとニゴールは1965年から1966年にかけてSimulaの普及に尽力し、スウェーデン、ドイツ、ソビエト連邦などでSimulaの使用が増加した。1968年には、バロース B5000上で広く利用されるようになり、後にはURAL-16コンピュータ上にも実装された。1966年、ダールとニゴールはSimulaのコンパイラを書いた。彼らは、SIMSCRIPT(自由形式の英語的な汎用シミュレーション言語)を実装に用いて、アントニー・ホーアのレコード・クラス概念を取り入れることに熱心に取り組んだが、彼らは、一般化されたプロセスの概念として、レコード・クラスの属性を保持する層と、接頭辞(prefix)の系列を保持する層の二層構造とする方式に辿り着いた。 接頭辞の系列を通じて、プロセスは先行する定義を参照し、それらの属性を追加することができる。このようにしてSimulaは、クラスとサブクラスの階層を導入し、これらのクラスからオブジェクトを生成することを可能にする方法を導入することとなった。[11]
1972年にはIBM System/360およびIBM System/370のIBMメインフレーム用にSimula 67コンパイラが完成[9]。同年、フランスのCII 10070およびCII Iris 80メインフレーム用のSimula 67コンパイラが無償で提供された。1974年には、Simulaユーザー会は23カ国のメンバーを有するまでになっていた。1975年初頭、DECsystem-10メインフレームファミリー用のSimula 67コンパイラが無償でリリースされ、同年8月までにDECsystem-10のSimula 67コンパイラは28サイトにインストールされた(そのうちの22サイトは北米)。オブジェクト指向のプログラミング言語としてSimulaは、貨物港における船舶と積載貨物の動きを調査・改善するための研究のような、物理モデリング研究に携わる研究者に主に利用されていた[9]。
この記事には独自研究が含まれているおそれがあります。 |
1974年にMITの計算機科学者バーバラ・リスコフは「抽象データ型」という概念を提唱し、上述のモジュールの共同詳細化をその振る舞いによって意味内容が決定される抽象データという考え方でより明解に形式化した。1975年に計算機科学者ニクラウス・ヴィルトは、モジュール機能を主題にした言語Modulaと共にモジュラルプログラミングを提唱した。このパラダイムでは、モジュールを仕様定義とコード/データ実装に分離しての、前者による抽象化と後者の情報隠蔽が備えられて、これはインターフェースの実装という概念の先例になっている。また、1970年代後半からIBM社を中心にした研究者たちが(エドワード・ヨードンなど)サブルーチンモジュールとデータ構造を連携させる構造化のパラダイムを発表し、こちらではモジュールの抽象指向は倦厭されて具象的な段階的詳細化が重んじられた。当時は具象指向の方に軍配が上がり、構造化開発は1980年代までのソフトウェア開発の主流になっている。このようにいささか奇妙ではあるが、Simulaのクラスとオブジェクトというプログラム概念は、プログラムモジュールの登場からモジュラルや構造化開発へといった進化の流れとは関係なく、しかもその前段階において生まれていた。
Simula発のProcessとクラスの示した可能性は、パロアルト研究所の計算機科学者アラン・ケイによる「メッセージング」という考え方のヒントになった。ケイはプログラム内のあらゆる要素をオブジェクトとして扱い、オブジェクトはメッセージの送受信でコミュニケーションするという独特のプログラム理論を提唱した。それには従来の関数呼び出しをセレクタの実行時解釈に置き換えて積極的な委譲を推進するメッセージ式と、プログラムコードとしても解釈できるデータ列を送信してそれを任意のタイミングで評価(eval)することで新たなデータを導出できるなどのアイディアが盛り込まれていた。これらの遅延結合パラダイムは非同期通信や単方向通信への可能性をも開いており、この発想の背景にはLISPの影響があった。メッセージを駆使するオブジェクトの構築には、Simula発のそれにプラトンのイデア論を重ね合わせたクラスとインスタンスの仕組みが導入された。オブジェクトとメッセージングの構想に基づいて開発された「Smalltalk」はプログラミング言語とGUIフレームワークを併せたものとなり、1972年にデータゼネラルNova上での1000行程度のBASICを使った試作(概念実証)を経て、翌1973年に新開発されたゼロックスAlto上で本格稼働された。Smalltalkの設計を説明するためにケイが考案した「オブジェクト指向」という用語はここで初めて発信された。またケイのメッセージング構想はMITの計算機科学者カール・ヒューイットに能動的なプロセス代数を意識させて[12]、1973年発表のアクターモデルのヒントにもなっている。しかし委譲の多用とデータ列が常にコード候補としても扱われる処理系は、当時のコンピュータには負荷が大きく実用的な速度を得られないという問題にすぐ直面した。Smalltalk-74(新たに開発されたBitBLTを使った高速描画版Smalltalk-72)からSmalltalk-76の過程で、やむなくメッセージは(多くの場合)関数の動的コールに、メソッドはパターンマッチ処理から単なる関数へ置き換えられるなど構想時の柔軟さが失われるほど最適化された。また、ケイの留保した継承機構[13]も導入されてオブジェクトは抽象データ型の性格も有するようになった。
上述のようにオブジェクト指向という言葉自体は、計算機科学者アラン・ケイによって作り出されている。Simula言語などにインスパイアされたケイが1967年頃に口にしたと伝えられるこの造語は[14]、彼が1972年から開発を始めた言語Smalltalkの設計を説明する過程で明確な用語として発信され、1981年頃から知名度を得るようになった。80年代半ばになるとオブジェクト指向の解釈は、元々のアラン・ケイによるSmalltalkの様式と、1983年に計算機科学者ビャーネ・ストロヴストルップが公開したC++の様式に二分された。前者ではメッセージングという概念が基礎にされ、後者ではSimula67由来の諸機能を加えた抽象データ型のスーパーセットが基礎にされていた。
1980年のSmalltalk-80は、元々はメッセージを重視していたケイを自嘲させるほど同期的で双方向的で手続き的なオブジェクト指向へと変貌していた。それでも動的ディスパッチと委譲でオブジェクトを連携させるスタイルは画期的であり、1994年に発表されるデザインパターンの模範にもされている。1981年に当時の著名なマイコン専門誌『BYTE』が、Smalltalkとその理念であるオブジェクト指向を紹介して世間の注目を集める契機になったが、ケイの思惑に反して技術的関心を集めたのはクラスの仕組みの方であった。オブジェクト指向は知名度を得るのと同時に、Simula発のクラス(継承と動的ディスパッチ)および抽象データ型(データ抽象とデータ隠蔽)にマウントされて解釈されるようになり、それらのコンセプトがケイの構想とは無関係であったことから、オブジェクト指向の定義はケイの手を離れて独り歩きするようになった。
Simulaを研究対象にしていたAT&Tベル研究所の計算機科学者ビャーネ・ストロヴストルップは、1979年からクラス付きC言語の制作に取り組み、1983年に「C++」を公開した。C++で実装されたクラスは、Simula由来の継承と仮想関数に加えて、段階的なレキシカルスコープの概念をクラス構造に応用したアクセスコントロールを備えていた。C++で確立されたアクセスコントロールは情報隠蔽によるデータ抽象を提示したが、コードスタイル上ほとんどザル化されており、その理由からストロヴストルップ自身もC++は正しくない(not just)オブジェクト指向言語であると明言している。1986年にソフトウェア技術者バートランド・メイヤーが制作した「Eiffel」の方は、正しいオブジェクト指向を標榜してクラスのデータ抽象を遵守させるコードスタイルが導入されていた。クラスメンバ(フィーチャー)は属性/手続き/関数の三種構成で、手続きで属性を変更して関数で属性を閲覧するという形式に限定されており、これは抽象データ型に忠実な実装であった。アクセスコントロールはC++のとは異なるクラス指名方式にされ、仮想関数機能は延期手続き/関数として実装された。
1986年からACMがOOPSLAを年度開催するようになり、オブジェクト指向は従来の構造化開発に代わる技術として明確に意識され始めた。OOPSLAのプログラミング言語セクションでは、抽象データ型を基礎にしたクラス・パラダイムが主要テーマにされ、それを標準化するための数々のトピックが議題に上げられている。モジュール分割、抽象化、再利用性、階層構造、複合構成、情報隠蔽、実行時多態、動的束縛、総称型、永続性、並行性、自動メモリ管理といったものがそうであり、参画した識者たちによる寄稿、出版、講演を通して世間にも広められた。そうした潮流の中でストロヴストルップはデータ抽象の重要性を訴え、リスコフは基底と派生に分けたデータ抽象の階層構造の連結関係(置換原則)について提言した。契約による設計と開放閉鎖原則を提唱するメイヤーが1988年に刊行した『オブジェクト指向ソフトウェア構築』によるEiffel式のクラス理論は高く評価され、Eiffelを現行の模範形とする声も多く上がった。ただしこれは学術寄りの意見でもあったようで、世間のプログラマの間では厳格なEiffelよりも、柔軟で融通の利くC++の人気の方が高まっていた。他方でアラン・ケイのメッセージ・メタファに忠実であろうとする動きもあり、1984年に制作された「Objective-C」はC言語をSmalltalk方向に拡張してメッセージ式を平易化した言語であった。1987年にパロアルト研究所で誕生した「Self」は、Smalltalkのクラスベース設計をより柔軟に平易化したプロトタイプベースを編み出している。
ネットワーク技術の発展に連れて、データとメソッドの複合体であるオブジェクトの概念は、分散システム構築のための基礎要素としての適性を特に見出される事になり、IBM社、Apple社、サン社などが1989年に共同設立したOMGは、企業システムネットワーク向け分散オブジェクトプログラミング規格となるCORBAを1991年に発表した。その前年にマイクロソフト社はウェブアプリケーション向けの分散オブジェクトプログラミング技術となるOLEを発表し、1993年にはCOMと称するソフトウェアコンポーネント仕様へと整備した。このCOMの利用を眼目にしてリリースされた「Visual C++」「Visual Basic」はウェブ時代の新しいプログラミング様式を普及させる先駆になった。この頃にデータ抽象、データ隠蔽、アクセスコントロールおよびインターフェースによるプログラムの抽象化は、総じてカプセル化の概念でまとめられるようになった。クラスの継承が最もオブジェクト指向らしい機能と見なされていたのが当時の特徴であった。継承構造を利用した振る舞いサブタイピング及び動的ディスパッチは多態性という用語に包括された。こうしていわゆるオブジェクト指向の三大要素がやや漠然と確立されている。1996年にサン社がリリースした「Java」は三大要素が強く意識されたクラスベースであり、その中の分散オブジェクト技術はBeansと呼ばれた。類似の技術としてApple社もMacOS上でObjective-Cなどから扱えるCocoaを開発している。また、1994年から96年にかけて「Python」「Ruby」「JavaScript」といったオブジェクト指向スクリプト言語がリリースされ、従来の静的型付けに対する動的型付けと、クラスベースに対する新しいプロトタイプベースの認知度を高めている。
抽象化を旨とするオブジェクト指向ではそのプログラミング自体の抽象化も積極的に推進されている。80年代後半から立ち上げられたオブジェクト指向分析(OOA)やオブジェクト指向設計(OOD)の各手法から導き出される概念モデルを、多角的にチャート化ないしダイアグラム化するための数々のオブジェクト指向開発方法論がOOPSLA界隈の識者たちから発表されるようになり、そこで用いられる形式言語はオブジェクトモデリング言語と呼ばれた。これはプログラミングのためのプロトタイプ(ひな型)として重視され、オブジェクト指向ではモデリング言語とプログラミング言語が並んでソフトウェア開発の両輪になった。1994年にモデリング言語によるGOFデザインパターンが初回発表され、これはオブジェクト指向教育で非常に重視されるようになった。1995年にモデリング言語の標準化を企図したUMLがOOPSLAで初回発表され、1997年にOMGの標準モデリング言語として採用された。同年にデザインパターンを帰納的に分析して九原則にまとめたGRASPが発表されている。
特徴
この記事には独自研究が含まれているおそれがあります。 |
OOPではクラスベースと呼ばれるスタイルが多数派である。他にプロトタイプベースと呼ばれる後発のスタイルもあるが、こちらは少数派である。クラスベースのOOP言語は、Smalltalk様式とC++様式で二分されており[要出典]、C++様式の方がずっと多数派である。C++様式は、静的型付けと動的型付けの分類で大別されている。それらの主な特徴を箇条書きするとこうなる。
- クラスベース - クラスのインスタンス化でオブジェクトを構築する。
- プロトタイプベース - オブジェクトのクローンでオブジェクトを構築する。クラスとインスタンスの相対性をオブジェクトから撤廃して、プロトタイプでオブジェクトを体系化している。動的型付け中心。動的バインディングによる多態性。
なお、場合によっては C言語などオブジェクト指向を支援しない言語でOOP的なプログラミングが行われることもある。
クラスとインスタンス
OOPの要点であるクラスは、データ構造とそれを扱うための操作・振る舞いをひとまとめにした一種のプログラムモジュール機能として定義されており、その実装はSimula67由来の継承と動的ディスパッチを加えた抽象データ型のスーパーセットにされていることが多い。クラスのデータ構造はレコード型や構造体に似た書式で定義されることが多く、データ構造の要素は言語ごとにフィールド、プロパティ、属性、メンバ変数などと呼ばれている。クラスに定義される操作・振る舞いはメソッドやメンバ関数などと呼ばれる。[要説明]
OOP言語のクラスと、そうでない言語でのモジュールの違いを知ることは、OOPを理解する上でも重要になる。どちらも手続きとデータの複合体であるが、クラスの第一の特徴はそれに継承が備えられていることであり、次にThis参照の機構と、継承構造上の内包的な動的ディスパッチである。その次になる情報隠蔽と、定義と実装に分離しての抽象化の機構は、OOP以前のモジュラルプログラミングからのものである。振る舞い抽象を担っているインターフェースの概念もそちらが先例であったが、データ抽象を担っているカプセル化(情報隠蔽とThis参照の融合)の採用はOOPが最初である。継承構造上の内包的な動的ディスパッチによるサブタイピング(=ポリモーフィズム)はOOP発祥であるが、それを純粋化すると前述のインターフェースになる。OOP以前の構造化開発のモジュールには情報隠蔽はあるが、継承はなく、カプセル化やポリモーフィズムといった抽象化の諸機構も持たない。なお、振る舞いサブタイピングは多重ディスパッチのOOPでは軽視されており、カプセル化は動的型付けのOOPではしばしば軽視されている。
C++様式のクラスベースはオブジェクトを、型理論に沿った[要出典] 型(type)と値(term)に分離している。その型の一種であるユーザー定義型(user defined type)がクラスにされており、クラスで型付けされた値がインスタンスになっている。ユーザー定義型とは構造体に似たデータ複合体であり[疑問点 ]、OOPでは手続き(のポインタ)もそのメンバにされている。クラスはインスタンスのひな型であり、インスタンスはクラスを実体化したものである。実体化=インスタンス化である。コンパイル時に型チェックされるユーザー定義型は静的型付けであり、実行時に型チェックされるユーザー定義型は動的型付けである。なお、Smalltalk様式のクラスベースは型理論の依存型に似ている。依存型は型と値の境界がない型付けである。
オブジェクトとは
クラスベース言語での「オブジェクト」は、インスタンスを指す用語として説明されているが、このような重複語になった背景にはOOP原点のSmalltalkの設計がある。Smalltalkは、全てのプログラム要素はオブジェクトであり、全てのオブジェクトはクラスのインスタンス化であり、クラスもまたオブジェクトであり、オブジェクトは他のオブジェクトと相互作用(interaction)すると定義していた。そこではクラスもまたメタクラス(型)のインスタンス化(値)になり、そのメタクラスもまた他のメタクラスのインスタンス化になっていたので、クラスとインスタンスは即ちオブジェクトの性質(相対性)を指すための言葉になっていた。これがC++様式では簡素化されて、クラスとインスタンスは型と値の役割に固定され、メタクラスはリフレクション機能に固定されたので、クラスとインスタンス化の相互再帰が失われたオブジェクトは、相互作用できるインスタンスを指しているままで放置された。相互作用とは各種演算と同義であり、Smalltalkのクラスは相互作用できる値でもあるのでオブジェクトであるが、C++様式のクラスはただの型なので演算対象に出来ないことからオブジェクトではなくなっている。
Smalltalk方言のSelfを原点とするプロトタイプベースは、オブジェクトからクラスとインスタンスの相対性を無くしたスタイルである。数値・文字列・配列・関数・シンボル・構造体(オブジェクト型)といった基本的な型は備えられているが、これはオブジェクト種類の区別に特化されたものなので、型理論に沿ったクラスベースのそれとは厳密には異なっている。クラス性質を除去したオブジェクトは事実上のインスタンスに一元化されており、その全てが相互作用(interaction)する。オブジェクトの表現はスロット(シンボルとコンテンツのペアデータ)の可変長配列でなされており、オブジェクトの識別は専らダックタイピングによってなされる。クラス概念が無いのでサブクラス化とインスタンス化は成立せず、代わりにクローン(複製)によってオブジェクトの継承がなされており、クローンはインスタンス化の代替になる。複製元オブジェクトは、複製先オブジェクトのプロトタイプと呼ばれる。
データ構造とそれを扱うためのメソッド群を情報隠蔽の概念と合わせてモジュール化(パッケージ化)するという手法がカプセル化と呼ばれる。カプセル化されたメソッドは、This値が暗黙の先頭引数として常に渡されるように実装される。This値とはクラスのデータ構造をメモリ展開するためのヒープ領域の基底アドレスを指しており、インスタンス化時に確定されたThis値によってメソッドは専用のデータ構造にアクセスできる。専用メソッドを通してのデータ構造の閲覧と変更は、抽象データ型の考え方に沿ったデータ構造の抽象化を意味することになり、これはデータ抽象と呼ばれる。データ閲覧用メソッドはゲッター/アクセッサと呼ばれ、データ変更用メソッドはセッター/ミューテイタと呼ばれる。
情報隠蔽とはそのクラスのデータ構造の各要素および各メソッドを必要に応じて内部隠蔽するという概念である。内部隠蔽されたデータ要素とメソッドはそのクラス外部からのアクセスが禁止される。抽象データ型本来の形式ではデータ構造のみが隠蔽対象になるので、これはデータ隠蔽とも呼ばれる。隠蔽指定外のデータ要素とメソッドは外部公開されて、そのクラス外部からもアクセス可能になる。外部公開の範囲を指定する機能はアクセスコントロールと呼ばれており、これが内部隠蔽の仕組みを担っている。クラスのレキシカルスコープを基準にした段階的なアクセス許可範囲は可視性と呼ばれる。可視性は無制限・任意クラスグループ限定・派生クラスグループ限定・自クラス限定(内部隠蔽)の四段階がUMLクラス図では標準にされている。
既存クラスのデータ/メソッド構成に、任意のデータ/メソッド構成を付け足して、既存構成+新規構成の新しいクラスを定義するという手法が継承と呼ばれる。また、各クラスの共通構成パートを括りだして特有構成パートと分離することでオブジェクトを分類体系化し、同時にその共通構成パートの記号化によってソースコード内の重複記述を削減する機能とも解釈される。これは差分プログラミング目的の継承であり、実装継承(implementation inheritance)とも呼ばれた。
リスコフ置換原則と開放/閉鎖原則が取り上げられると、既存構成に抽象メソッドを置いて新規構成にその実装メソッドを置くというメソッドオーバーライドを用いるための振る舞いサブタイピング目的の継承の方が重視されるようになり、これは界面継承(interface inheritance)とも呼ばれた。メソッド定義の引き継ぎとサブタイピングを中心にしたIs-a関係主体の継承をUMLクラス図は特化(specialization)と定義している。
既存クラスはスーパークラス・親クラス・基底クラスなどと呼ばれ、新しいクラスはサブクラス・子クラス・派生クラスなどと呼ばれる。親と子は差分プログラミング重視で、基底と派生はサブタイピング重視で用いられる。継承できるクラスが一つに限られている単一継承を採用している言語と、継承できるクラスの数に制限がない多重継承を採用している言語がある。抽象メソッドを持つクラスは抽象クラスと呼ばれる。基底クラス側でリターン型とパラメータのみが定義されて実行コードブロックが未定義のままの抽象メソッドは、その派生クラス側の実装メソッドでオーバーライドされる。オーバーライドは遅延結合による多相な複雑系アルゴリズムを表現するオープン再帰(open recursion)のメカニズムにもなっている。
抽象メソッドのみで構成される純粋抽象クラスはインターフェースと呼ばれ、その継承をUMLクラス図は実装(implementation)と定義している。インターフェースの実装は、サブタイピングのIs-a関係を完全順守させるメカニズムである。また、クラスへの機能注入を目的にして、主に具象メソッド群をクラスに継承させるというアプローチもあり、これはミックスイン(mix-in)と呼ばれる。mix-inのメソッド集合体は、トレイトの形態にされることが多い。mix-inはUMLクラス図では扱われていない継承関係である。
異なる種類のクラスに共通の操作インターフェースを持たせてオブジェクトの振る舞いを抽象化するという手法がポリモーフィズム(多態性)と呼ばれる。OOPで語られる多態性はもっぱら継承構造を利用したサブタイプ多相を対象にしているが、アドホック多相もサポート的に用いられており、パラメトリック多相はコンポジションで用いられている。そのサブタイプ多相の設計としては、コンパイル時に確定されたメソッド名から呼び出されるプロセス内容が実行時に決定されるという仕組みを指しており、一つのメソッド名からその実行時状態に合わせた個別のメソッド処理が呼び出されるようにするという演繹的意味と、各クラスの同種機能メソッドを一つの共通メソッドにまとめて実行時状態に合わせたメソッド処理が呼び出されるようにするという帰納的意味がある。
その実装としてはメソッドオーバーライド機能を活用した仮想関数と、実行時パターンマッチング機能を活用した総称関数の二つが挙げられる。仮想関数はスーパークラスの抽象メソッドの呼び出しを、それをオーバーライドしたサブクラスの実体メソッドの呼び出しにつなげるという動的ディスパッチ機能である。総称関数はオブジェクトの実行時パターンマッチングを使用する独立関数であり、その引数にされた各オブジェクトの型(=クラス)の組み合わせに従って実行コードブロックを選択決定するという多重ディスパッチ機能である。同名アルゴリズムを個々の派生クラスのメンバ関数に分散記述するのが仮想関数であり、個々の派生クラスの同名アルゴリズムを一つの独立関数に一括記述するのが総称関数である。
コンポジションとデリゲーションとジェネリクス
コンポジション (合成)とデリゲーション(委譲)は、OOPでは継承と対比される機能である。継承(特化)はIs-a関係の暗黙委譲、合成はHas-a関係の明示委譲と読み替えることができる。合成とは、特定処理の委譲先になる部品クラスの1個以上を持たせたクラス構造であり、そのクラスがとある処理を要求されてそれに対応できるデータ/メソッドを持っていない場合は、それに対応できる部品クラスを選択して処理を委譲するという仕組みである。その要求判別と選択過程を自動サーチ化したものが継承であり、部品クラスを基底クラスに置き換えて暗黙の委譲先にしたものである。しかしその自動サーチは、クラス階層に分散配置されているデータ/メソッドのどれが実際にアクセスされるのかという把握を困難にしたので、ここで差分プログラミング用途の継承の欠点が取り沙汰されるようになり、その後のクラスの機能拡張と分類体系化では、継承と合成の使い分けが重視されるようになった。また、Has-a関係はUMLクラス図では合成(composition)と集約(aggregation)に分けられている。
ジェネリクス(総称化)は、オブジェクトのデータ構造を汎用化して、それに汎用アルゴリズムの数々を適用できるようにした技術である。様々なデータ要素を内包するコンポジション(合成)オブジェクトはコンテナ(List/Set/Mapなど)と呼ばれ、その要素の型を型変数化することで汎用的なデータ構造を表現し、その要素の型はコンテナのインスタンス化時に与えられる型パラメータによって決定される。ジェネリクスはデータ構造とアルゴリズムを個別化しての柔軟なコンポーネント性を促進させ、反復子の方法論を確立した。また、圏論の圏に見立てられたコンテナおよび対象に見立てられたデータ要素の入れ子構造と、射に見立てられたサブタイピングの融合は、共変性と反変性の手法に発展した。
動的ディスパッチとメッセージパッシング
動的ディスパッチは、OOPのポリモーフィズムの原型機能であり、コンパイル時に確定されたメソッド名から呼び出されるメソッド内容(実行コードブロック)が、実行時に選択決定(ディスパッチ)される仕組み全般を指している。メソッドに与えられた各引数の型の組み合わせに従って、実行コードブロックが選択決定される仕組みのシングルディスパッチと多重ディスパッチを包括している。先頭引数の型パターンマッチング固定でディスパッチされるのはシングルになり、そうでないならば多重になる。例えば仮想関数はThisのシングルディスパッチである。
メッセージパッシングでは引数の型に加えて、メソッド名も実行時に解釈される要素にされており、そこでただのシンボルとして扱われるメソッド名はセレクタと呼ばれている。セレクタはメッセージ式を基本文とするSmalltalk様式のOOPで用いられる。object selector: param
ような書式でオブジェクトの共通窓口になるメッセージレシーバーに、セレクタと引数値で構成されたメッセージが送られる。また、object.call(method_name, param)
のような書式でオブジェクトの共通窓口関数をコールするのもメッセージパッシングと呼ばれる。これはRPCやORBなどの分散オブジェクト技術で用いられている。メソッド名(関数名)も実行時に解釈されるという特徴を指してメッセージパッシングと呼ぶ。メッセージレシーバーでは、渡されたセレクタのパターンマッチングに従って実行コードブロックがディスパッチされることが多く、OOP原点のSmalltalkは、引数とThisが与えられるその実行コードブロックをメソッドと呼んでいた。
インターフェースとトレイト
インターフェースは、カプセル化と継承のサブタイピング用法を促進した機能である。情報隠蔽とデータ抽象とメソッド抽象を合わせて表現する。クラスから見たインターフェースは自身のサービスのモデル化である。OOPのインターフェースは基本的には抽象メソッドのみで構成される抽象型と定義されている。その実装方式は純粋抽象クラスが基本形にされており、インスタンス化はできない継承専用クラスになって多重継承が前提にされている。インターフェースの抽象メソッドは、その実装クラスの同名具象メソッドでオーバーライドされる。インターフェースの各抽象メソッドはセッター・ゲッター・プロセスとして動作し、その実装内容は隠蔽されて実行時ごとに決定される。その代表使用例はソフトウェアコンポーネント間の相互通信媒体である。
OOP原点のSmalltalk処理系由来のトレイトは、クラスへの機能注入を目的にしたメソッドの集合体であり、トレイトの多重継承を扱う作法はミックスインと呼ばれている。トレイトの継承はインクルードともされ、これはUMLクラス図の”特化”と”実装”ではない第三の継承概念になるので、従来の標準OOP路線からは外れていた。後の依存性逆転の原則および依存性の注入のデザインパターンでは、Mix-inの作法が注目され、そこでのトレイトの役割を与えたインターフェースの応用設計が扱われている。そのMix-inをUMLクラス図は、特定の機能(サーバーやデータベースなど)から”実現”されたインターフェース(依存対象)に向けてオブジェクトが”関連”するという図式にしている。この手法は分散オブジェクト技術の後継としてのDIコンテナで用いられている。
デザインパターン一覧
継承と振る舞いサブタイピング
継承がIs-a関係を表現して、サブクラスのインスタンスはスーパークラスのインスタンスを安全に置換できるという直感は、多くのOOP言語には当てはまっておらず、ミュータブルなオブジェクトを扱っていても同様である。型チェック機構付きのサブタイプ多相は、振る舞いサブタイピングの正当性までを保証しない。一般的に振る舞いサブタイピングは非決定性なので、そのための言語機能の実装は非現実的であり、クラスまたはオブジェクトの継承関係の設計は、プログラマの手によって注意深く行われる必要がある。スーパークラスとサブクラス間の理想的な振る舞いサブタイピングを実現するためのデザインパターンとしてよく知られているのが、リスコフの置換原則である。
GOFデザインパターン
1994年に”Gang of Four”がその著作で発表した23のデザインパターンは、余りに有名である。
- 生成のパターン
- 構造のパターン
- 振る舞いのパターン
責任駆動設計とデータ駆動設計
OOPで提唱された責任駆動設計(RDD)とは、特定の機能を実現する責任およびその機能が共有する情報に基づいて、クラスを定義していくデザインパターンである。責任駆動設計では、振る舞い抽象としてのクラスに焦点を当てており、必然的にインターフェースや抽象クラスが多用されることになる。
OOPにおけるデータ駆動設計とは、保持するデータ構造に基づいて、クラスを定義していくデザインパターンである。データ駆動設計では、データ抽象としてのクラスに焦点を当てており、カプセル化と抽象データ型の概念に重きが置かれる。レベッカ・ウーフ‐ブロックによって彼女の責任駆動設計と、従来のデータ駆動設計は対比されるようになっている。
SOLID、GRASPのガイドライン
SOLIDのガイドラインは、プログラミングにおける五つの実践の頭文字をとった語呂合わせであり、マイケル・C・フェザーズ[15]が考案し提唱したものである
- S:単一責任の原則(英語版)
- O:開放/閉鎖原則
- L:リスコフの置換原則
- I:インターフェイス分離の原則(英語版)
- D:依存性逆転の原則
GRASP(General Responsibility Assignment Software Patterns)は、クレーグ・ラーマンが提唱したもう一つガイドラインである。
公式意味論
数々の識者によってOOPで扱われる概念を公式化する試みが行われている。OOP概念の解釈に用いられる代表的なコンセプトは以下の通りである。
- F余代数(F-coalgebra)
- 抽象データ型(abstract data type) - 存在型を含む。なお、動的ディスパッチはサポートしていない。
- 再帰データ型(recursive type)
- カプセル化状態(encapsulated state)
- 継承(inheritance)
- レコード(record)- 関数リテラルを持つレコードがオブジェクトと見なされるが、本格的なOOPになるにはそれ以上の複雑さが必要である。
”オブジェクト”の共通認識的な定義または理論を見つけようとする試みはそれほど成功していない。ルカ・カーデリらによるA Theory of Objects[16]は、比較的成功している例とされる。
オブジェクト指向言語一覧
ここではクラスベースの記述は省略している。
- Simula67 1967年 静的
- Smalltalk 1972年 動的・メッセージ式・純粋系
- C++ 1983年 静的
- Objective-C 1984年 静的と動的・メッセージ式
- Object Pascal 1986年 静的
- Eiffel 1986年 静的・純粋系
- Self 1987年 動的・プロトタイプベース・メッセージ式・純粋系
- Modula-3 1988年 静的
- Common Lisp(CLOS) 1988年(ANSI規格化は1994年) 動的・多重ディスパッチ・メタオブジェクト
- Oberon-2 1991年 静的
- Dylan 1992年 動的・多重ディスパッチ
- Lua 1993年 動的・プロトタイプベース
- Python 1994年(ver1.0) 動的
- Delphi 1995年 静的
- Ada 1995年からOOP化 静的
- Perl 1995年からOOP化 動的
- Ruby 1995年 動的・純粋系
- Java 1996年(ver1.0) 静的
- JavaScript 1996年(first released) 動的・プロトタイプベース
- OCaml 1996年 静的・関数型
- Squeak 1996年 動的・メッセージ式
- ECMAScript 1997年 動的・プロトタイプベース
- C# 2000年 静的と動的
- Visual Basic.NET 2001年 静的
- D言語 2001年 静的
- Io 2002年 動的・プロトタイプベース・メッセージ式・純粋系
- COBOL 2002年からOOP化 静的
- FORTRAN 2003年からOOP化 静的
- R言語 2003年からOOP化 動的・関数型・多重ディスパッチ
- Scala 2003年 静的・関数型
- Groovy 2003年 動的
- PHP 2004年からOOP化 静的と動的
- F# 2005年 静的・関数型
- MATLAB 2008年からOOP化 動的・関数型
- Go 2009年 静的
- Rust 2010年 静的・関数型
- Kotlin 2011年 静的
- Ceylon 2011年 静的
- Dart 2011年 静的・関数型
- Elixir 2011年 動的・関数型
- Julia 2012年 動的・関数型・多重ディスパッチ
- TypeScript 2012年 静的と動的・関数型
- Swift 2014年 静的・プロトコル指向
- Raku 2015年 静的と動的
用語一覧
ここでは日本語ページ化されている項目のみ列挙している。
- クラスベース
- プロトタイプベース
- メッセージ
- クラス
- インスタンス
- フィールド
- プロパティ
- メソッド
- インスタンス変数
- クラス変数
- コンストラクタ
- デストラクタ
- カプセル化
- 継承
- 多態性
- This
- Is-a
- Has-a
- サブタイピング
- ダックタイピング
- ミックスイン
- スーパークラス
- サブクラス
- 抽象クラス
- メタクラス
- オーバーライド
- 仮想関数テーブル
- 菱形継承問題
- 仮想継承
- インターフェース
- トレイト
- 抽象型
- オブジェクト型
- 型クラス
- 委譲
- 多重ディスパッチ
- ダブルディスパッチ
- オーバーロード
- アノテーション
- コンテナ
- ボックス化
- ジェネリクス
- 共変性と反変性
- モジュール
- ソフトウェアコンポーネント
- リフレクション
- モンキーパッチ
- メッセージ転送
- イミュータブル
- 型システム
- オブジェクト指向分析設計
- オブジェクト指向モデリング
- UML
- 契約による設計
- GOFデザインパターン
- リファクタリング
- 依存性の注入
脚注
- ^ Kindler, E.; Krivy, I. (2011). Object-Oriented Simulation of systems with sophisticated control. International Journal of General Systems. pp. 313–343.
- ^ Lewis, John; Loftus, William (2008). Java Software Solutions Foundations of Programming Design 6th ed. Pearson Education Inc.. ISBN 978-0-321-53205-3, section 1.6 "Object-Oriented Programming"
- ^ McCarthy, J.; Brayton, R.; Edwards, D.; Fox, P.; Hodes, L.; Luckham, D.; Maling, K.; Park, D. et al. (March 1960). LISP I Programmers Manual. en:Boston, en:Massachusetts: Artificial Intelligence Group, en:M.I.T. Computation Center and Research Laboratory. p. 88f. オリジナルの17 July 2010時点におけるアーカイブ。 . "In the local M.I.T. patois, association lists [of atomic symbols] are also referred to as "property lists", and atomic symbols are sometimes called "objects"."
- ^ McCarthy, John; Abrahams, Paul W.; Edwards, Daniel J.; Hart, swapnil d.; Levin, Michael I. (1962). LISP 1.5 Programmer's Manual. en:MIT Press. p. 105. ISBN 978-0-262-13011-0 . "Object — a synonym for atomic symbol"
- ^ a b “Dr. Alan Kay on the Meaning of "Object-Oriented Programming"” (2003年). 11 February 2010閲覧。
- ^ Sutherland, I. E. (30 January 1963). “Sketchpad: A Man-Machine Graphical Communication System”. Technical Report No. 296, Lincoln Laboratory, Massachusetts Institute of Technology via Defense Technical Information Center (stinet.dtic.mil). 17 July 2019閲覧。
- ^ The Development of the Simula Languages, en:Kristen Nygaard, en:Ole-Johan Dahl, p.254 Uni-kl.ac.at
- ^ Ross, Doug. “The first software engineering language”. LCS/AI Lab Timeline. MIT Computer Science and Artificial Intelligence Laboratory. 13 May 2010閲覧。
- ^ a b c Holmevik, Jan Rune (1994). “Compiling Simula: A historical study of technological genesis”. IEEE Annals of the History of Computing 16 (4): 25–37. doi:10.1109/85.329756. オリジナルの30 August 2017時点におけるアーカイブ。 3 March 2018閲覧。.
- ^ {{Cite book|last = Dahl |first = Ole Johan|year = 2004 |chapter-url = http://www.mn.uio.no/ifi/english/about/ole-johan-dahl/bibliography/the-birth-of-object-orientation-the-simula-languages.pdf |doi = 10.1007/978-3-540-39993-3_3|access-date =3 March 2018 |chapter = The Birth of Object Orientation: The Simula Languages|title = From Object-Orientation to Formal Methods|volume = 2635|pages = 15–25|series = Lecture Notes in Computer Science|isbn = 978-3-540-21366-6|citeseerx = 10.1.1.133.6730}|access-date = 21 October 2021}
- ^ Nygaard, Kristen (1978). “The Development of the SIMULA Languages”. ACM SIGPLAN Notices 13 (8): 245–272. doi:10.1145/960118.808391 22 October 2021閲覧。.
- ^ “Our research has concentrated on the development of a rigorous model of computation based on relationship among computational events. The development of this model has been greatly influenced by Seymour Papert's “little people” model of computation, a seminar given by Alan Key at M.I.T. on an early version of Smalltalk, and the work of Church, Fischer, Landin, on formalisms based on the lambda calculus.”Induction and Meta-evaluation
- ^ “I didn't like the way Simula I or Simula 67 did inheritance (though I thought Nygaard and Dahl were just tremendous thinkers and designers). So I decided to leave out inheritance as a built-in feature until I understood it better. ”Alan Kay on the Meaning of “Object-Oriented Programming”
- ^ “At Utah sometime after Nov 66 when, influenced by Sketchpad, Simula, the design for the ARPAnet, the Burroughs B5000, and my background in Biology and Mathematics, I thought of an architecture for programming. It was probably in 1967 when someone asked me what I was doing, and I said: "It's object-oriented programming".”Alan Kay on the Meaning of “Object-Oriented Programming”
- ^ https://wiki.c2.com/?MichaelFeathers
- ^ Abadi, Martin、Cardelli, Luca『A Theory of Objects』Springer-Verlag New York, Inc.、1996年。ISBN 978-0-387-94775-4 。