「オブジェクト指向プログラミング」の版間の差分
→継承: 誤字修正 タグ: モバイル編集 モバイルウェブ編集 |
|||
(同じ利用者による、間の2版が非表示) | |||
9行目: | 9行目: | ||
'''オブジェクト指向プログラミング'''(オブジェクトしこうプログラミング、{{Lang-en-short|''object-oriented programming''}}、略語:OOP)とは、互いに密接な関連性を持つ[[変数 (プログラミング)|データ]]と[[メソッド (計算機科学)|メソッド]]をひとつにまとめて[[オブジェクト (プログラミング)|オブジェクト]]とし、それぞれ異なる性質と役割を持たせたオブジェクトの様々な定義と、それらオブジェクトを相互に作用させる様々なプロセスの設定を通して、プログラム全体を構築するソフトウェア開発手法である。 |
'''オブジェクト指向プログラミング'''(オブジェクトしこうプログラミング、{{Lang-en-short|''object-oriented programming''}}、略語:OOP)とは、互いに密接な関連性を持つ[[変数 (プログラミング)|データ]]と[[メソッド (計算機科学)|メソッド]]をひとつにまとめて[[オブジェクト (プログラミング)|オブジェクト]]とし、それぞれ異なる性質と役割を持たせたオブジェクトの様々な定義と、それらオブジェクトを相互に作用させる様々なプロセスの設定を通して、プログラム全体を構築するソフトウェア開発手法である。 |
||
'''[[オブジェクト指向]]'''という用語自体は、計算機科学者[[アラン・ケイ]]によって生み出されている。1962年公開の言語「[[Simula]]」にインスパイアされたケイが咄嗟に口にしたとされるこの造語は、彼が1972年から開発公開を始めた「[[Smalltalk]]」の言語設計を説明する中で発信されて1981年頃から知名度を得た。しかしケイが示したオブジェクト指向の要点である[[メッセージパッシング]]の考え方はさほど認知される事はなく、代わりに[[クラス (コンピュータ)|クラス]]と[[オブジェクト (プログラミング)|オブジェクト]]という仕組みを注目させるだけに留まっている。同時にケイの手から離れたオブジェクト指向は[[抽象データ型]]を中心にした解釈へと推移していき、1983年に計算機科学者[[ビャーネ・ストロヴストルップ]]が公開した「[[C++]]」が好評を博したことで、オブジェクト指向に対する世間の理解は「[[C++]]」とそのモデルの「[[Simula|Simula 67]]」のスタイルで定着した。それに基づいて[[カプセル化]]、[[継承 (プログラミング)|継承]]、[[ポリモーフィズム |
'''[[オブジェクト指向]]'''という用語自体は、計算機科学者[[アラン・ケイ]]によって生み出されている。1962年公開の言語「[[Simula]]」にインスパイアされたケイが咄嗟に口にしたとされるこの造語は、彼が1972年から開発公開を始めた「[[Smalltalk]]」の言語設計を説明する中で発信されて1981年頃から知名度を得た。しかしケイが示したオブジェクト指向の要点である[[メッセージパッシング]]の考え方はさほど認知される事はなく、代わりに[[クラス (コンピュータ)|クラス]]と[[オブジェクト (プログラミング)|オブジェクト]]という仕組みを注目させるだけに留まっている。同時にケイの手から離れたオブジェクト指向は[[抽象データ型]]を中心にした解釈へと推移していき、1983年に計算機科学者[[ビャーネ・ストロヴストルップ]]が公開した「[[C++]]」が好評を博したことで、オブジェクト指向に対する世間の理解は「[[C++]]」とそのモデルの「[[Simula|Simula 67]]」のスタイルで定着した。それに基づいて[[カプセル化]]、[[継承 (プログラミング)|継承]]、[[ポリモーフィズム]]といった考え方も後年に確立された。 |
||
== 特徴 == |
== 特徴 == |
||
16行目: | 16行目: | ||
#[[カプセル化]](''encapsulation'') |
#[[カプセル化]](''encapsulation'') |
||
#[[継承 (プログラミング)|継承]](''inheritance'') |
#[[継承 (プログラミング)|継承]](''inheritance'') |
||
#[[ポリモーフィズム |
#[[ポリモーフィズム]](''polymorphism'') |
||
#[[メッセージ (コンピュータ)|メッセージパッシング]](''message passing'') |
#[[メッセージ (コンピュータ)|メッセージパッシング]](''message passing'') |
||
23行目: | 23行目: | ||
=== 継承 === |
=== 継承 === |
||
既存オブジェクトのデータ構成とメソッド構成を引き継いで、新しい派生オブジェクトを定義する仕組みが継承と呼ばれる。引き継ぐ際には新たなデータとメソッドを自由に追加できるので、派生オブジェクトの構成は既存要素+追加要素になる。既存 |
既存オブジェクトのデータ構成とメソッド構成を引き継いで、新しい派生オブジェクトを定義する仕組みが継承と呼ばれる。引き継ぐ際には新たなデータとメソッドを自由に追加できるので、派生オブジェクトの構成は既存要素+追加要素になる。ここでの既存オブジェクトは基底オブジェクトと読み替えられる。基底は親、派生は子とも読み替えられる。継承が重視されるオブジェクトは、型として用いられるクラスであることが多い。クラスベースでは基底をスーパークラス、派生をサブクラスと呼ぶ。一つのスーパークラスを継承するのは単一継承と呼ばれる。複数のスーパークラスを継承してそれぞれの要素を引き継ぐのは多重継承と呼ばれる。[[統一モデリング言語|UML]]では汎化と特化の関係で表現されている。メソッドの抽象化に焦点を当てた継承の方は{{仮リンク|実装継承|en|Inheritance_(object-oriented_programming)}}などと呼ばれる。UMLでは実現と実装の関係で表現されている。実装継承は特定のオブジェクトたちに共通した振る舞い側面を抜き出して抽象化する仕組みを指し、その抽象オブジェクトは[[インタフェース (抽象型)|インターフェース]]、[[トレイト]]、{{仮リンク|プロトコル(OOP)|en|Protocol (object-oriented programming)|label=プロトコル}}などと呼ばれる。 |
||
=== |
=== ポリモーフィズム === |
||
異なる種類のオブジェクトに同一の操作インターフェースを持たせる仕組みが多態性と呼ばれる。オブジェクト指向下の |
異なる種類のオブジェクトに同一の操作インターフェースを持たせる仕組みがポリモーフィズム(多態性)と呼ばれる。オブジェクト指向下のポリモーフィズムは、クラスの派生関係またはオブジェクトの動的バインディング機能によって、コンパイル時のメソッド名から呼び出されるプロセス内容が実行時に決定されるという仕組みの{{仮リンク|振る舞いサブタイピング|en|Behavioral subtyping}}を指す。これは{{仮リンク|サブタイプ多相|en|Subtyping}}の一種である。その代表格は{{仮リンク|仮想関数(OOP)|en|Virtual function|label=仮想関数}}であり、オブジェクト指向でポリモーフィズムと言えばこれを指して説明されることが多い。仮想関数は、メソッドが所属するクラスの派生関係のみに焦点を当てた一重ディスパッチであり、スーパークラス抽象メソッドの呼び出しを、それを[[オーバーライド]]したサブクラス実装メソッドの呼び出しにつなげる機能である。一重ディスパッチとはプロセス選択に関与するオブジェクトが一つであることを意味しており、二つ以上の場合は[[多重ディスパッチ]]になる。多重の方はメソッドが属するクラスの派生関係だけでなく、そのメソッドの各引数のクラスの派生関係にも注目した形態であり、各引数は実行時の型判別と[[ダウンキャスト]]されて、その引数型の組み合わせに対応したプロセスを選択する。一重ディスパッチと多重ディスパッチは{{仮リンク|動的ディスパッチ|en|Dynamic dispatch|label=}}という分類用語に包括されており、仮想関数は[[クラスベース]]向けに特化された動的ディスパッチとも定義されている。クラス機構の代わりにプロトタイプ機構を用いる[[プロトタイプベース]]の方では、オブジェクト(フレーム)のメソッド名スロットに当てはめられるメソッド実装の参照が随時切り替えられることにより、そのメソッド名から呼び出されるプロセスが実行時に決定されるという仕組みで広義の振る舞いサブタイピングを表現している。この仕組みも動的ディスパッチという分類用語に包括されており、便宜的にそのまま動的ディスパッチと呼ばれることが多い。 |
||
=== メッセージパッシング === |
=== メッセージパッシング === |
||
41行目: | 41行目: | ||
=== Smalltalkとオブジェクト指向の誕生(1972 - 81) === |
=== Smalltalkとオブジェクト指向の誕生(1972 - 81) === |
||
SimulaのProcess |
Simula発のProcessとクラスの仕様は、[[パロアルト研究所]]の計算機科学者[[アラン・ケイ]]によるオブジェクト重視と「メッセージング」という考え方のヒントになった。ケイはプログラム内のあらゆる要素をオブジェクトとして扱い、オブジェクトはメッセージの送受信でコミュニケーションするという独特のプログラム理論を提唱した。それには関数適用風の書式を用いたオブジェクト同士の多種多様な[[委譲|デリゲーション]]と、プログラムコードとしても解釈できるデータ列を送信してそれを評価(''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]]が |
<br>(Smalltalkはその構文やライブラリやクラスをも関心にしていないという事だけではない。多くの人の関心を小さなアイディアに向かせたことから、僕はオブジェクトという用語を昔作り出したことを残念に思っている。大切なのはメッセージングなんだ。)|Alan Kay}}1980年のSmalltalk-80は、元々はメッセージを重視していたケイを自嘲させるほど同期的で双方向的で手続き的なオブジェクト指向へと変貌していた。それでも動的ディスパッチと[[委譲]]でオブジェクトを連携させるスタイルは画期的であり、1994年に発表される[[デザインパターン (ソフトウェア)|デザインパターン]]の模範にもされている。1981年に当時の著名なマイコン専門誌『[[Byte (magazine)|BYTE]]』がSmalltalkとケイ提唱のオブジェクト指向を紹介して世間の注目を集める契機になったが、ケイの思惑に反して技術的関心を集めたのはクラス機構の方であった。オブジェクト指向は知名度を得るのと同時に、Simula発の[[クラス (コンピュータ)|クラス]]とそれを理論面から形式化した[[抽象データ型]]を中心に解釈されるようになり、それらの考案者がケイの構想とは無関係であったことから、オブジェクト指向の定義はケイの手を離れて独り歩きするようになった。 |
||
=== C++の開発(1979 - 88) === |
=== C++の開発(1979 - 88) === |
||
[[Simula]]を研究対象にしていた[[ベル研究所|AT&Tベル研究所]]の計算機科学者[[ビャーネ・ストロヴストルップ]]は、1979年からクラス付きC言語の開発に取り組み、1983年に「[[C++]]」を公開した。C++で実装された[[クラス (コンピュータ)|クラス]]は、Simula譲りの[[継承 (プログラミング)|継承]]と仮想関数に加えて、[[レキシカルスコープ]]の概念をクラス定義とその継承構造に応用したアクセスコントロールを備えていた。C++で確立されたアクセスコントロールはカプセル化の元になったがコードスタイル上ほとんどザル化されており、その理由からストロヴストルップ自身もC++は正しくない(''not just'')オブジェクト指向言語であると明言している。1986年にソフトウェア技術者[[バートランド・メイヤー]]が開発した「[[Eiffel]]」の方は、正しいオブジェクト指向を標榜してクラスのデータ抽象を遵守させるコードスタイルが導入されていた。クラスメンバ(フィーチャー)は属性、手続き、関数の三種構成で、手続きで属性を変更し関数で属性を参照するという形式に限定されており、これは抽象データ型の[[セマンティクス|振る舞い意味論]]に沿った実装であった。アクセスコントロールはC++のアクセス修飾子による段階的レキシカルスコープ定義に対して、自身のクライアントクラスを定義する書式になり、これはモジューラプログラミングの情報隠蔽論に沿った実装であった。C++の仮想関数は延期 |
[[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をモデルにしてそれを平易化した言語であった。そのメッセージレシーバーはメソッドリストにないセレクタを受け取った場合にのみ動的ディスパッチ機構に移るというスタイルで形式化された。メッセージレシーバの仕組みは[[遠隔手続き呼出し]]/[[Object Request Broker|オブジェクト要求ブローカー]]の実装に適していたので[[分散システム]]とオブジェクト指向の親和性を認識させることになった。 |
<br />(僕はオブジェクト指向という言葉を作ったけど、C++(のような言語)は考えていなかった)|Alan Kay}}1986年から[[Association for Computing Machinery|ACM]]が[[OOPSLA|オブジェクト指向会議]](OOPSLA)を年度開催し、そのプログラミング言語セクションでは[[抽象データ型]]の流れを汲む[[クラス (コンピュータ)|クラス]]・パラダイムが主要テーマにされ、それを標準化するための数々のトピックが議題に上げられている。[[モジュール性]]、情報隠蔽、[[抽象化 (計算機科学)|抽象化]]、再利用性、[[継承 (プログラミング)|階層構造]]、複合構成、実行時多態、[[動的束縛]]、[[総称型]]、[[ガベージコレクション|自動メモリ管理]]といったものがそうであり、参画した識者たちによる寄稿、出版、講演を通して世間にも広められた。そうした潮流の中で[[ビャーネ・ストロヴストルップ|ストロヴストルップ]]はデータ抽象の重要性を訴え、[[バーバラ・リスコフ|リスコフ]]は[[上位概念、下位概念、同位概念および同一概念|基底と派生]]に分けたデータ抽象の[[リスコフの置換原則|階層構造の連結関係]]について提言した。[[契約による設計]]を提唱する[[バートランド・メイヤー|メイヤー]]が1988年に刊行した『オブジェクト指向ソフトウェア構築』は名著とされ、Eiffelを現行の模範形とする声も多く上がった。ただしこれは学術寄りの意見でもあったようで、世間のプログラマの間では厳格なEiffelよりも柔軟で融通の利くC++の人気の方が高まっていた。また、Smalltalk発のメッセージ・メタファを重視しようとする流れの中で、クラスのメソッド呼び出しをオブジェクトにメッセージを送ることになぞらえる考え方が広まった。これは実行時の選択メソッドをメッセージの発送先にする意味合いで、動的/一重/多重ディスパッチの呼称の由来になっている。他方でSmalltalkの仕様に忠実であろうとする動きもあり、1984年に計算機科学者ブラッド・コックスが開発した「[[Objective-C]]」はSmalltalkをモデルにしてそれを平易化した言語であった。そのメッセージレシーバーはメソッドリストにないセレクタを受け取った場合にのみ動的ディスパッチ機構に移るというスタイルで形式化された。メッセージレシーバの仕組みは[[遠隔手続き呼出し]]/[[Object Request Broker|オブジェクト要求ブローカー]]の実装に適していたので[[分散システム]]とオブジェクト指向の親和性を認識させることになった。 |
||
=== プロトタイプベースの考案(1985 - 90) === |
=== プロトタイプベースの考案(1985 - 90) === |
||
[[Smalltalk]]のオブジェクト指向は |
[[Smalltalk]]のオブジェクト指向は[[アラン・ケイ]]がその影響を言及していた[[LISP]]コミュニティを感化して、Smalltalkが示した万物をオブジェクトとして扱う{{仮リンク|メタオブジェクトプロトコル|en|Metaobject|label=}}を[[LISP]]プログラミングに融合させようとする潮流を生みだした。これはLISPの基礎情報要素であるシンボル型の集合体となるオブジェクトを構築し、シンボル型であるメンバ変数名/メンバ関数名を実行時にその都度評価(''eval'')してその変数実体の参照/関数実体の呼出につなげるという構想から、フレームと呼ばれるデータ構造体のスロットに変数ポインタ/関数ポインタを付け替えするという実装などにまとめられた。シンボル型がマッピングされるスロットは増設削減でき、実例元クラスと継承元クラス用のスロットも加えられた。これらは機能名としては[[メタクラス]]と呼ばれた。これらのメタオブジェクトプロトコルを導入して、1985年に[[MIT人工知能研究所]]の[[LISPマシン]]上で「Flavors」が実装された。スロットにマッピングされたシンボル型の判別による[[動的型付け]]の[[ダックタイピング]]の概念が生まれ、またシンボル型のマッピング構成を部品化して多重継承させるという[[ミックスイン]]の機能も考案された。1988年にFlavorsの言語機能を[[Common Lisp]]に融合させた「[[CLOS]]」が公開されたが、こちらは関数を中心にして[[抽象データ型]]から距離を置いたスタイルになった。FlavorsおよびCLOSの発表と並行して[[パロアルト研究所]]では、計算機科学者デビッド・アンガーがSmalltalkの方言として制作する「[[Self]]」を1987年に初回稼働して1990年に一般公開した。Selfに導入されたメタオブジェクトプロトコルは、後に[[プロトタイプベース]]またはインスタンスベースと呼ばれるパラダイムに発展する。同時にそれと、従来の[[クラス (コンピュータ)|クラス]]機構を中心にしたオブジェクト指向言語を区別するための[[クラスベース]]という言葉も生まれた。 |
||
=== コンポーネントとネットワーク(1989 - 97) === |
=== コンポーネントとネットワーク(1989 - 97) === |
||
55行目: | 55行目: | ||
== 代表的なオブジェクト指向言語 == |
== 代表的なオブジェクト指向言語 == |
||
オブジェクト指向言語は、[[抽象データ型]] |
オブジェクト指向言語は、[[抽象データ型]]に準拠した[[クラスベース]]、{{仮リンク|メタオブジェクトプロトコル|en|Metaobject|label=}}を採用した[[プロトタイプベース]]、[[Smalltalk]]を規範にした[[メッセージパッシング|メッセージング]]ベースの三タイプに分類されるのが一般的である。[[クラスベース]]では「C++」「Java」「C#」が代表的である。[[プロトタイプベース]]では「Python」「JavaScript」「Ruby」が有名である。[[メッセージパッシング|メッセージング]]ベースでは「Smalltalk」「Objective-C」「Self」などがある。言語仕様の中でオブジェクト指向の存在感が比較的高い代表的なプログラミング言語は以下の通りである。 |
||
[[ファイル:History of object-oriented programming languages.svg|境界|中央|フレームなし]] |
[[ファイル:History of object-oriented programming languages.svg|境界|中央|フレームなし]] |
||
;[[Simula|Simula 67]] 1967年 |
;[[Simula|Simula 67]] 1967年 |
||
:1962年に公開された[[Simula]]の後継バージョンであり、[[クラス (コンピュータ)|クラス]]のプログラム概念を導入した最初の言語である。物理モデルを解析するシミュレーション制作用に開発されたもので、クラスをメモリに展開したオブジェクトはその観測対象要素になった。Simulaのクラスは、一つのローカル変数構造と複数のプロシージャをまとめたミニモジュールと言えるものであったが、継承と仮想関数という先進的な設計を備えていた事でオブジェクト指向言語の草分けと見なされるようになった。[[クラスベース]]の源流である。 |
:1962年に公開された[[Simula]]の後継バージョンであり、[[クラス (コンピュータ)|クラス]]のプログラム概念を導入した最初の言語である。物理モデルを解析するシミュレーション制作用に開発されたもので、クラスをメモリに展開したオブジェクトはその観測対象要素になった。Simulaのクラスは、一つのローカル変数構造と複数のプロシージャをまとめたミニモジュールと言えるものであったが、継承と仮想関数という先進的な設計を備えていた事でオブジェクト指向言語の草分けと見なされるようになった。[[クラスベース]]の源流である。 |
||
;[[Smalltalk]] 1972年 |
;[[Smalltalk]] 1972年 |
||
:[[メッセージパッシング]]のプログラム概念を導入した最初の言語。数値、真偽値、文字列から変数、コードブロック、メタデータまでのあらゆる要素をオブジェクトとするアイディアを編み出した最初の言語で |
:[[メッセージパッシング|メッセージング]]のプログラム概念を導入した最初の言語。数値、真偽値、文字列から変数、コードブロック、メタデータまでのあらゆるプログラム要素をオブジェクトとするアイディアを編み出した最初の言語であり、[[プロトタイプベース]]の源流にもなった。オブジェクト指向という言葉はSmalltalkの言語設計を説明する中で生み出された。オブジェクトにメッセージを送るという書式であらゆるプロセスを表現することが目標にされている。動的ディスパッチと[[ダイナミックバインディング|動的バインディング]]相当の機構である[[メッセージ転送|メッセージレシーバー]]と[[委譲|デリゲーション]]は、後年の[[デザインパターン (ソフトウェア)|デザインパターン]]のモデルにもされた。GUI運用環境に統合された専用のランタイム環境上で動作させる設計も模範にされ、これは後に[[仮想マシン]]や[[仮想実行システム]]と呼ばれるものになる。 |
||
;[[C++]] 1983年 |
;[[C++]] 1983年 |
||
:[[C言語]]に[[クラスベース]]のオブジェクト指向を追加したもの。Simulaの影響を受けている。[[静的型付け]]の[[クラス (コンピュータ)|クラス]]が備えられてカプセル化、継承、多態性の三仕様を実装している。カプセル化ではアクセス修飾子とフレンド指定子の双方から可視性を定義できる。継承は多重継承、オーバーライド制約用の継承可視性、[[菱形継承問題]]解決用の[[仮想継承]]も導入されている。多態性は[[仮想関数]]によるサブタイプ多相、[[テンプレート (プログラミング)|テンプレートクラス&関数]]によるパラメトリック多相、[[多重定義|関数&演算子オーバーロード]]によるアドホック多相が導入されている。元がC言語であるため、オブジェクト指向から逸脱したコーディングも多用できる点が物議を醸したが、その是非はプログラマ次第であるという結論に落ち着いた。 |
:[[C言語]]に[[クラスベース]]のオブジェクト指向を追加したもの。Simulaの影響を受けている。[[静的型付け]]の[[クラス (コンピュータ)|クラス]]が備えられてカプセル化、継承、多態性の三仕様を実装している。カプセル化ではアクセス修飾子とフレンド指定子の双方から可視性を定義できる。継承は多重継承、オーバーライド制約用の継承可視性、[[菱形継承問題]]解決用の[[仮想継承]]も導入されている。多態性は[[仮想関数]]によるサブタイプ多相、[[テンプレート (プログラミング)|テンプレートクラス&関数]]によるパラメトリック多相、[[多重定義|関数&演算子オーバーロード]]によるアドホック多相が導入されている。元がC言語であるため、オブジェクト指向から逸脱したコーディングも多用できる点が物議を醸したが、その是非はプログラマ次第であるという結論に落ち着いた。 |
||
;[[Objective-C]] 1984年 |
;[[Objective-C]] 1984年 |
||
:[[C言語]]に[[メッセージパッシング|メッセージ]] |
:[[C言語]]に[[メッセージパッシング|メッセージング]]ベースのオブジェクト指向を追加したもの。こちらはSmalltalkの影響を受けており、それに準じた[[メッセージパッシング]]の書式が備えられた。メッセージを受け取るクラスの定義による[[静的型付け]]と共に、メッセージを[[委譲]]するオブジェクトの実行時決定による[[動的型付け]]も設けられている。オブジェクト指向的にはC++よりも正統と見なされた。[[制御構造|制御構造文]]が追加され、メッセージ構文も平易化されており、Smalltalkよりも扱いやすくなった。 |
||
;[[Object Pascal]] 1986年 |
;[[Object Pascal]] 1986年 |
||
:[[Pascal]]にクラスベースのオブジェクト指向を追加したもの。当初はモジュールのデータ隠蔽的なカプセル化、単一継承、仮想関数による多態性という基本的なものだった。静的型付け重視である。[[ニクラウス・ヴィルト|ヴィルト]]監修の[[アップル (企業)|アップル社]]による初回バージョンを土台にして様々な企業団体による派生版が公開されており、その特徴と機能追加も様々である。 |
:[[Pascal]]にクラスベースのオブジェクト指向を追加したもの。当初はモジュールのデータ隠蔽的なカプセル化、単一継承、仮想関数による多態性という基本的なものだった。静的型付け重視である。[[ニクラウス・ヴィルト|ヴィルト]]監修の[[アップル (企業)|アップル社]]による初回バージョンを土台にして様々な企業団体による派生版が公開されており、その特徴と機能追加も様々である。 |
||
70行目: | 70行目: | ||
:[[C++]]の柔軟性と融通性とは正反対のオブジェクト指向言語。[[クラスベース]]で[[静的型付け]]重視である。[[契約プログラミング|契約による設計]]に基づく[[表明|アサーション]]の挿入でクラスの状態および演算用の引数と返り値を細かくチェックできる。[[例外処理]]も備えられている。クラスメンバ(フィーチャー)はデータ、アクセッサ、ミューテイタの三種限定で[[多重定義|オーバーロード]]はできない。カプセル化の可視性は自身に依存するクラス(クライアント)を定義する形で決められる。多重継承可能であり、クラス間の繋がりを[[仮想継承]]機能、各種[[オーバーライド]]指定子、名前衝突を解決するリネーミング機能などで綿密に設定できる。多態性は[[仮想関数|延期関数/手続き]](サブタイプ多相)と[[ジェネリックプログラミング|ジェネリシティ]](パラメトリック多相)である。[[ガーベジコレクション]]機能が初めて導入されたオブジェクト指向言語でもある。 |
:[[C++]]の柔軟性と融通性とは正反対のオブジェクト指向言語。[[クラスベース]]で[[静的型付け]]重視である。[[契約プログラミング|契約による設計]]に基づく[[表明|アサーション]]の挿入でクラスの状態および演算用の引数と返り値を細かくチェックできる。[[例外処理]]も備えられている。クラスメンバ(フィーチャー)はデータ、アクセッサ、ミューテイタの三種限定で[[多重定義|オーバーロード]]はできない。カプセル化の可視性は自身に依存するクラス(クライアント)を定義する形で決められる。多重継承可能であり、クラス間の繋がりを[[仮想継承]]機能、各種[[オーバーライド]]指定子、名前衝突を解決するリネーミング機能などで綿密に設定できる。多態性は[[仮想関数|延期関数/手続き]](サブタイプ多相)と[[ジェネリックプログラミング|ジェネリシティ]](パラメトリック多相)である。[[ガーベジコレクション]]機能が初めて導入されたオブジェクト指向言語でもある。 |
||
;[[Self]] 1987年 |
;[[Self]] 1987年 |
||
:[[メッセージパッシング|メッセージ]] |
:[[メッセージパッシング|メッセージング]]ベースのオブジェクト指向言語でSmalltalkの方言として開発された。それ故にプロトタイプからプロトタイプを派生させ、またインスタンスを複製してそれにプロパティとメソッドを[[ダイナミックバインディング|動的バインディング]]できるというメタオブジェクトプロトコルも忠実に実装された。[[プロトタイプベース]]というパラダイムはこのSelfから認知されるようになった。[[動的型付け]]重視である。Smalltalkと同様に専用のランタイム環境上で実行され、GUI運用環境の構築も目標にしていた。Selfのランタイム環境は[[実行時コンパイラ]]機能を初めて実装したことで知られており画期的な処理速度を実現している。この技術は[[Java仮想マシン]]の土台になった。 |
||
;[[Common Lisp]]([[CLOS]]) 1988年(ANSI規格化は1994年) |
;[[Common Lisp]]([[CLOS]]) 1988年(ANSI規格化は1994年) |
||
:[[クラスベース]]のオブジェクト指向。メソッド記述の関数呼び出し形式への統合、[[多重ディスパッチ]]、クラスの動的な再定義等を特徴とする。 |
:[[クラスベース]]のオブジェクト指向。メソッド記述の関数呼び出し形式への統合、[[多重ディスパッチ]]、クラスの動的な再定義等を特徴とする。 |
||
;[[Python]] 1994年 |
;[[Python]] 1994年 |
||
:[[プロトタイプベース]]のオブジェクト指向スクリプト言語。[[基本データ型]]や[[コンテナ (データ型)|コレクション型]]などよく使われるデータ要素を全て組み込みのオブジェクトにして |
:[[プロトタイプベース]]のオブジェクト指向スクリプト言語。[[基本データ型]]や[[コンテナ (データ型)|コレクション型]]などよく使われるデータ要素を全て組み込みのオブジェクトにしている。それらは[[手続き型プログラミング|手続き型]]スタイルでも気軽に扱える。コレクション型を扱うのに適した[[関数型プログラミング|関数型]]構文も導入されている。関数もオブジェクトなので柔軟に扱える。オブジェクトは自由にプロパティとメソッドを付け替えして様々に応用できるようデザインされている。オブジェクトは[[ダックタイピング]]で型判別されるので変数ないし関数の型宣言と型注釈は撤廃されている。ゆえに[[動的な型付け|動的型付け]]重視である。Pythonのプロトタイプはクラスと呼ばれている。多重継承可能であり親要素の参照順序はC3線形化で解決されている。アクセスコントロールはなくデータ抽象を軽視するコードスタイルと相まってカプセル化は備えられていない。多態性はメソッドの動的バインディングで行われる。後期バージョンで型ヒントが追加され、それに伴い[[ジェネリクス]]も導入された。 |
||
;[[Java]] 1995年 |
;[[Java]] 1995年 |
||
:[[C++]]をモデルにしつつ堅牢性とセキュリティを重視した[[クラスベース]]のオブジェクト指向言語。静的型付け重視である。パッケージ中心のカプセル化、単一のみの継承、仮想関数と多重実装可な[[インタフェース (抽象型)|インターフェース]]による多態性と、基本に忠実なクラスベースである。C++風の[[ポインタ (プログラミング)|ポインタ]]と値型インスタンスは除外されて参照型インスタンスに統一した。[[例外処理]]を整備し[[演算子オーバーロード]]を除外した。オブジェクト指向と[[マルチスレッド]]の調和が図られ、[[ソフトウェアコンポーネント|コンポーネント指向]]による動的クラスローディングの存在感が高められている。クラスメタデータを操作できる[[リフレクション (情報工学)|リフレクション]]は初期から採用された。中期から[[ジェネリクス]](パラメトリック多相)と[[アノテーション|メタアノテーション]](アドホック多相)が導入され、ラムダ式と関数型インターフェースを軸にした[[関数型言語|関数型構文]]も採用された。[[仮想マシン]]上で実行される。[[仮想マシン]]と[[ガーベジコレクション]]の技術は比較的高度と見なされている。 |
:[[C++]]をモデルにしつつ堅牢性とセキュリティを重視した[[クラスベース]]のオブジェクト指向言語。静的型付け重視である。パッケージ中心のカプセル化、単一のみの継承、仮想関数と多重実装可な[[インタフェース (抽象型)|インターフェース]]による多態性と、基本に忠実なクラスベースである。C++風の[[ポインタ (プログラミング)|ポインタ]]と値型インスタンスは除外されて参照型インスタンスに統一した。[[例外処理]]を整備し[[演算子オーバーロード]]を除外した。オブジェクト指向と[[マルチスレッド]]の調和が図られ、[[ソフトウェアコンポーネント|コンポーネント指向]]による動的クラスローディングの存在感が高められている。クラスメタデータを操作できる[[リフレクション (情報工学)|リフレクション]]は初期から採用された。中期から[[ジェネリクス]](パラメトリック多相)と[[アノテーション|メタアノテーション]](アドホック多相)が導入され、ラムダ式と関数型インターフェースを軸にした[[関数型言語|関数型構文]]も採用された。[[仮想マシン]]上で実行される。[[仮想マシン]]と[[ガーベジコレクション]]の技術は比較的高度と見なされている。 |
||
86行目: | 86行目: | ||
:[[Java]]を強く意識してマイクロソフト社が開発したクラスベースのオブジェクト指向言語。Javaよりも[[マルチパラダイムプログラミング言語|マルチパラダイム]]の性質が強化されており、言語仕様も比較的大規模と言える。ステートメント書式と各種データ型の取り扱いに、C++風の柔軟性と融通的を残しながら様々な[[糖衣構文]]サポートも加えてコーディング上の利便性がより高められている。[[マルチスレッド]]仕様も整備されている。アドホック多相では拡張メソッド、インデクサ、演算子オーバーロードなどを備えている。パラメトリック多相では[[共変性と反変性 (計算機科学)|共変/反変]]も扱える[[ジェネリクス]]を備えている。サブタイプ多相はクラスは単一継承でインターフェースは多重実装と基本通りである。[[関数型言語|関数型構文]]も整備されており、特にメソッド参照機能であるデリゲートの有用性が高められている。デリゲートは[[イベント駆動型プログラミング|イベント駆動構文]]の平易な表現も可能にしている。基本は[[静的型付け]]であるが、動的束縛型と[[ダックタイピング]]による[[動的型付け]]の存在感が高められているので漸進的型付けの言語と見なされている。[[.NET Framework]]([[共通言語基盤]]=仮想実行システム)上で実行される。 |
:[[Java]]を強く意識してマイクロソフト社が開発したクラスベースのオブジェクト指向言語。Javaよりも[[マルチパラダイムプログラミング言語|マルチパラダイム]]の性質が強化されており、言語仕様も比較的大規模と言える。ステートメント書式と各種データ型の取り扱いに、C++風の柔軟性と融通的を残しながら様々な[[糖衣構文]]サポートも加えてコーディング上の利便性がより高められている。[[マルチスレッド]]仕様も整備されている。アドホック多相では拡張メソッド、インデクサ、演算子オーバーロードなどを備えている。パラメトリック多相では[[共変性と反変性 (計算機科学)|共変/反変]]も扱える[[ジェネリクス]]を備えている。サブタイプ多相はクラスは単一継承でインターフェースは多重実装と基本通りである。[[関数型言語|関数型構文]]も整備されており、特にメソッド参照機能であるデリゲートの有用性が高められている。デリゲートは[[イベント駆動型プログラミング|イベント駆動構文]]の平易な表現も可能にしている。基本は[[静的型付け]]であるが、動的束縛型と[[ダックタイピング]]による[[動的型付け]]の存在感が高められているので漸進的型付けの言語と見なされている。[[.NET Framework]]([[共通言語基盤]]=仮想実行システム)上で実行される。 |
||
;[[Scala]] 2003年 |
;[[Scala]] 2003年 |
||
:[[クラスベース]]のオブジェクト指向と[[関数型プログラミング]]を融合させた言語。[[クラス (コンピュータ)|クラス]]機構と関数型の[[型システム]]に同等の比重が置かれており静的型付け重視である。[[ミックスイン]]相当の[[トレイト]]と、[[共変性と反変性 (計算機科学)|共変/反変]]および抽象タイプメンバを扱える[[ジェネリクス]]を連携させた多態性が重視されておりオブジェクトを様々に[[派生型|派生型付け]]できる。シングルトンオブジェクトの役割が形式化されて従来のクラス静的メンバの新解釈にも用いられている。専用の定義書式により[[イミュータブル]]なオブジェクトが重視されている。上述の派生型付けスタイルとオブジェクト引数の[[逆写像|抽出]]構文 |
:[[クラスベース]]のオブジェクト指向と[[関数型プログラミング]]を融合させた言語。[[クラス (コンピュータ)|クラス]]機構と関数型の[[型システム]]に同等の比重が置かれており静的型付け重視である。[[ミックスイン]]相当の[[トレイト]]と、[[共変性と反変性 (計算機科学)|共変/反変]]および抽象タイプメンバを扱える[[ジェネリクス]]を連携させた多態性が重視されておりオブジェクトを様々に[[派生型|派生型付け]]できる。シングルトンオブジェクトの役割が形式化されて従来のクラス静的メンバの新解釈にも用いられている。専用の定義書式により[[イミュータブル]]なオブジェクトが重視されている。上述の派生型付けスタイルとオブジェクト引数の[[逆写像|抽出]]構文と[[パターンマッチング|パターンマッチング式]]の併用連鎖計算は[[モナド (プログラミング)|モナド]]を彷彿とさせて独特の関数型スタイルを表現できる。[[Java仮想マシン]]上で動作するJavaテクノロジ互換言語である。 |
||
;[[Kotlin]] 2011年 |
;[[Kotlin]] 2011年 |
||
:静的型付けの[[クラスベース]]のオブジェクト指向であるが、[[手続き型プログラミング]]に回帰しており、クラス枠外の関数とグローバル変数の存在感が高められている。クラスはpublicアクセスとfinal継承がデフォルトにされて、カプセル化と継承が公然と軽視されている。これによりインスタンスは手続き型の関数の対象値としての役割が強められ、その操作をサポートする関数型構文も導入されている。仮想関数と抽象クラスによる多態性は標準通りである。[[Java仮想マシン]]上で動作するJavaテクノロジ互換言語である。 |
:静的型付けの[[クラスベース]]のオブジェクト指向であるが、[[手続き型プログラミング]]に回帰しており、クラス枠外の関数とグローバル変数の存在感が高められている。クラスはpublicアクセスとfinal継承がデフォルトにされて、カプセル化と継承が公然と軽視されている。これによりインスタンスは手続き型の関数の対象値としての役割が強められ、その操作をサポートする関数型構文も導入されている。仮想関数と抽象クラスによる多態性は標準通りである。[[Java仮想マシン]]上で動作するJavaテクノロジ互換言語である。 |
||
96行目: | 96行目: | ||
== 用語と解説 == |
== 用語と解説 == |
||
;[[クラス (コンピュータ)|クラス]] |
;[[クラス (コンピュータ)|クラス]] |
||
: |
:(''class'')の仕組みを中心にしたオブジェクト指向を[[クラスベース]]と言う。クラスはデータメンバとメソッドをまとめたものであり、[[プログラム意味論|操作的意味論]]を付加された静的[[構造体|レコード]]とも解釈される。クラスはインスタンスのひな型であり、インスタンスはクラスを実例化(量化)したものである。クラスはカプセル化、継承、多態性の三機能を備えていることが求められている。カプセル化はデータメンバとメソッドの可視性を指定する機能である。継承は自身のスーパークラスを指定する機能である。多態性はオーバーライドと[[仮想関数テーブル]]を処理する機能である。コンストラクタとデストラクタの実装も必要とされている。前者はインスタンス生成時に、後者はインスタンス破棄時に呼び出されるメソッドである。 |
||
;プロトタイプ |
;プロトタイプ |
||
: |
:(''prototype'')の仕組みを中心にしたオブジェクト指向を[[プロトタイプベース]]と言う。プロトタイプとは識別名&中間参照ペアの集合体を指す。この集合体は一般にフレームと呼ばれる。識別名&中間参照ペアの割り当て箇所は一般にスロットと呼ばれる。スロットにはデータメンバとメソッドの識別名&中間参照ペアが代入されるので、プロトタイプはクラスと同様にデータメンバとメソッドをまとめたものになる。プロトタイプは言語によってはクラスと呼ばれている。プログラマはシステムが提供する基底プロトタイプに、自由にデータメンバとメソッドを付け足して任意の派生プロトタイプを作成できる。プロトタイプは「型」相当であり、それを複製する方式で生成されるインスタンスは「値」相当である。データメンバとメソッドはその参照にインスタンスを必要とするものと、しないものに分かれる。前者はインスタンスメンバ、後者は静的メンバに相当するものである。インスタンスにも自由にデータメンバとメソッドを付け足すことができる。インスタンスはそのプロトタイプへの参照を保持しており、プロトタイプはその親プロトタイプへの参照を保持している。これは継承相当の機能になっている。インスタンスへの自由なメンバ付け替えは多態性相当の機能になっている。ただしプロトタイプは動的な関数型言語由来の仕様なので、クラスを用いるOOPの三大要素とはまた違った視点から眺める必要がある。 |
||
;[[メッセージ (コンピュータ)|メッセージ]] |
;[[メッセージ (コンピュータ)|メッセージ]] |
||
:オブジェクト指向で言われるメッセージ(''message'')は、複数方面の考え方が混同されている曖昧な用語になっている。元々はSmalltalkから始まったメッセージ |
:オブジェクト指向で言われるメッセージ(''message'')は、複数方面の考え方が混同されている曖昧な用語になっている。元々はSmalltalkから始まったメッセージングベースのオブジェクト指向の中心メカニズムである。以前はクラスベースの方でもメソッドの呼び出しをメッセージを送るという具合に考えることが推奨されていた。メッセージはオブジェクトのコミュニケーション手段と標榜されているが、その忠実な実装内容はそれほど知られていないのが実情である。最も混同されているものに[[アクターモデル]]があるが、そこで言われる非同期性とオブジェクト指向で言われる遅延性は現行の実装スタイルではそれほど共通していない。[[リモートプロシージャコール]]と[[Object Request Broker|オブジェクトリクエストブローカー]]の働き方もメッセージパッシングと呼ばれることが多いが、その仕様と機能は動的ディスパッチに該当するものである。メッセージのオブジェクト指向的運用はメッセージングと名付けられているが、普通にメッセージパッシングとも呼ばれている。具体的な機能例としてはSmalltalk、Objective-C、Selfの[[メッセージ転送|メッセージレシーバー]]と、Rubyのメソッドミッシングなどがある。ただしこれらは[[アラン・ケイ]]のメッセージング構想の忠実な再現にまでは到っていない。 |
||
;[[インスタンス]] |
;[[インスタンス]] |
||
:(''instance'')はクラスベースではクラスを実 |
:(''instance'')はクラスベースではクラスを実例化(量化)したものであり、実装レベルで言うとデータメンバ群と仮想関数テーブルをメモリ上に展開したものになる。プロトタイプベースではプロトタイプを複製する方式で生成されたオブジェクトを指す。実装レベルで言うとメモリ上に展開された識別名&中間参照ペアの動的配列になる。 |
||
;[[フィールド (計算機科学)|データメンバ]] |
;[[フィールド (計算機科学)|データメンバ]] |
||
:(''data member'')はクラスまたはオブジェクトに属する変数。言語によってフィールド、プロパティ、メンバ変数、属性と呼ばれる。データメンバは、クラスデータメンバとインスタンスデータメンバに分かれる。クラスデータメンバは静的データメンバとも呼ばれる。その中で定数化されたものはクラス[[定数 (プログラミング)|定数]]と呼ばれる。クラスデータメンバはクラス名の名前空間でスコープされたグローバル変数と同じものであり、プログラム開始時から終了時まで確保される。インスタンスデータメンバはインスタンス生成時にメモリ上に確保されるものであり、その破棄時に消滅する。プロトタイプベースではプロトタイプ |
:(''data member'')はクラスまたはオブジェクトに属する変数。言語によってフィールド、プロパティ、メンバ変数、属性と呼ばれる。データメンバは、クラスデータメンバとインスタンスデータメンバに分かれる。クラスデータメンバは静的データメンバとも呼ばれる。その中で定数化されたものはクラス[[定数 (プログラミング)|定数]]と呼ばれる。クラスデータメンバはクラス名の名前空間でスコープされたグローバル変数と同じものであり、プログラム開始時から終了時まで確保される。インスタンスデータメンバはインスタンス生成時にメモリ上に確保されるものであり、その破棄時に消滅する。インスタンスデータメンバの参照にはそのthis参照が必要である。プロトタイプベースでは、プロトタイプで定義されたデータメンバでそのアクセスにインスタンス(self)を必要としないものが静的データメンバになる。 |
||
;[[メソッド (計算機科学)|メソッド]] |
;[[メソッド (計算機科学)|メソッド]] |
||
:(''method'')はクラスまたはオブジェクトに属する関数。言語によってはメンバ関数とも呼ばれる。データメンバの参照に特化したものはゲッター(''getter'')アクセッサ(''accessor'')と呼ばれる。データメンバの変更に特化したものはセッター(''setter'')ミューテイタ(''mutator'')と呼ばれる。メソッドは、クラスメソッドとインスタンスメソッドに分かれる。クラスメソッドは静的メソッドとも呼ばれる。クラスメソッドはクラス名の名前空間でスコープされたグローバル関数と同じものである。インスタンスメソッドを呼び出すにはその |
:(''method'')はクラスまたはオブジェクトに属する関数。言語によってはメンバ関数とも呼ばれる。データメンバの参照に特化したものはゲッター(''getter'')アクセッサ(''accessor'')と呼ばれる。データメンバの変更に特化したものはセッター(''setter'')ミューテイタ(''mutator'')と呼ばれる。メソッドは、クラスメソッドとインスタンスメソッドに分かれる。クラスメソッドは静的メソッドとも呼ばれる。クラスメソッドはクラス名の名前空間でスコープされたグローバル関数と同じものである。インスタンスメソッドを呼び出すにはそのthis参照が必要である。プロトタイプベースでは、プロトタイプで定義されたメソッドでそのアクセスにインスタンス(self)を必要としないものが静的メソッドになる。 |
||
;[[コンストラクタ]] |
;[[コンストラクタ]] |
||
:(''constructor'')はインスタンス生成時に呼び出されるそのクラスのメソッドである。インスタンスデータメンバを任意の値で初期化するためのものであるが、その他の初期化コードも記述できる。プロトタイプベースではシステム提供プロトタイプが保持する生成用メソッドまたは生成用のグローバル関数がコンストラクタ相当になる。 |
:(''constructor'')はインスタンス生成時に呼び出されるそのクラスのメソッドである。インスタンスデータメンバを任意の値で初期化するためのものであるが、その他の初期化コードも記述できる。プロトタイプベースではシステム提供プロトタイプが保持する生成用メソッドまたは生成用のグローバル関数がコンストラクタ相当になる。 |
||
147行目: | 147行目: | ||
;[[メタクラス]] |
;[[メタクラス]] |
||
:(''metaclass'') |
:(''metaclass'')は{{仮リンク|メタオブジェクトプロトコル|en|Metaobject|label=}}に準拠した機能名であり、実装方式は言語毎に違いがある。メタクラスは、クラスのデータメンバ、メソッド、スーパークラス、内部クラスなどの定義情報を記録した[[メタデータ]]である。メタクラスのインスタンス(実例化)がクラスになる。クラスベースのメタクラス機能は、実装レベルではシステム側が用意している特別なシングルトンオブジェクトと考えた方が分かりやすい。それにはほとんどの場合システム側が提供する抽象インターフェースを通してのみアクセスできる。メタクラスの情報を参照ないし変更できる機能はリフレクションと呼ばれる。メタクラスの変更はその実例クラスに直ちに反映される。プロトタイプベースのメタクラス機能では、メタクラスもプログラマが自由に扱えるオブジェクトになるので、メタクラスのそのまたメタクラスを定義できる[[形而上学|形而上]]関係も存在し、基底メタクラスと派生メタクラスを定義できる[[継承 (プログラミング)|継承]]関係も存在する。またメタクラス/クラスの実体を指す「eigenclass」といったプログラム概念も存在する。 |
||
;[[リフレクション (情報工学)|リフレクション]] |
;[[リフレクション (情報工学)|リフレクション]] |
||
:(''reflection'')は、メタクラスの |
:(''reflection'')は、メタクラスの内容を参照または変更する機能であるが、言語ごとに変更できる内容の範囲は異なっている。データメンバではデータ型、識別子、可視性が変更対象になる。メソッドではリターン型、識別子、パラメータリスト、可視性、仮想指定が変更対象になる。双方の追加定義と削除もできる事がある。スーパークラスも変更できる事がある。また、実行時の文字列(char配列やString)をデータメンバとメソッドの内部識別子として解釈できる機能もリフレクションに当たる。これは実行時の文字列によるデータメンバの参照とメソッドの呼び出しを可能にする。 |
||
;[[アノテーション|メタアノテーション]] |
;[[アノテーション|メタアノテーション]] |
||
:(''metadata annotation'')はクラスに任意の情報を埋め込める機能である。情報とは文字列と数値からなるキーワード、シンボル、テキストである。プログラマが自由な形式で書き込んで随時読み取るものであるが、システムから認識される形式のものもある。実装レベルではメタクラスに書き込まれてリフレクション機能またはその[[糖衣構文]]で読み取ることになる。[[マーカーインタフェース|マーカーインターフェース]]の拡張とも見なされている。メタアノテーションはクラス単位だけでなく、言語によってはインスタンス単位やメソッド単位でも埋め込むことができる。アドホック多相とされる。 |
:(''metadata annotation'')はクラスに任意の情報を埋め込める機能である。情報とは文字列と数値からなるキーワード、シンボル、テキストである。プログラマが自由な形式で書き込んで随時読み取るものであるが、システムから認識される形式のものもある。実装レベルではメタクラスに書き込まれてリフレクション機能またはその[[糖衣構文]]で読み取ることになる。[[マーカーインタフェース|マーカーインターフェース]]の拡張とも見なされている。メタアノテーションはクラス単位だけでなく、言語によってはインスタンス単位やメソッド単位でも埋め込むことができる。アドホック多相とされる。 |
||
168行目: | 168行目: | ||
:(''monkey patch'')はモジュールやスクリプトファイルなどの動的ローディングを用いて、インタプリタ実行後またはコンパイル後のソースコード内容を変化させる手法である。ソースコードに特定のフィルター処理を記述しておき、その中で任意の箇所を動的ローディングされたモジュール内のクラスや関数や変数で置き換えさせる事で、その時の配置モジュールに合わせた処理内容の変化ができる。モジュールを外せばフィルター処理は無効になる。この置き換え(パッチ当て)は遅延バインディング相当である。ソースコードを変えなくてよいのが条件である。 |
:(''monkey patch'')はモジュールやスクリプトファイルなどの動的ローディングを用いて、インタプリタ実行後またはコンパイル後のソースコード内容を変化させる手法である。ソースコードに特定のフィルター処理を記述しておき、その中で任意の箇所を動的ローディングされたモジュール内のクラスや関数や変数で置き換えさせる事で、その時の配置モジュールに合わせた処理内容の変化ができる。モジュールを外せばフィルター処理は無効になる。この置き換え(パッチ当て)は遅延バインディング相当である。ソースコードを変えなくてよいのが条件である。 |
||
;[[ジェネリクス]] |
;[[ジェネリクス]] |
||
:(''generics'')は、クラスメンバの任意の「型」を総称化したままのクラス定義を可能にし、そのクラスをインスタンス化する各構文箇所で「型」の詳細を決定できるようにしたコンパイル時の静的な機能である。言語によっては[[テンプレート (プログラミング)|テンプレート]](''template'')と呼ばれる。「型」とはデータメンバの型 |
:(''generics'')は、クラスメンバの任意の「型」を総称化したままのクラス定義を可能にし、そのクラスをインスタンス化する各構文箇所で「型」の詳細を決定できるようにしたコンパイル時の静的な機能である。言語によっては[[テンプレート (プログラミング)|テンプレート]](''template'')と呼ばれる。ここでの「型」とはデータメンバの型やメソッドの引数値/返り値/計算値の型を指している。クラス内のそれらを総称化して型変数にし、コンストラクタ呼び出し時の仮型引数に実型引数を適用すると、型変数に実型引数を当てはめたインスタンスが生成される。総称化された型を持つクラスはジェネリッククラスと呼ばれる。特定の型に依存しないクラスを汎用的に定義できるので、型が違うだけの重複コードを削減できるという利点がある。パラメトリック多相とされる。言語によっては、ジェネリッククラス同士を[[共変性と反変性 (計算機科学)|共変性と反変性]]による継承関係で結ぶことができる。これはジェネリッククラスに適用する実型引数の継承関係を、そのジェネリッククラス同士の継承関係にシフトする仕組みである。<code>class 猫 extends 動物</code>とすると<code>List<猫></code>は<code>List<動物></code>のサブクラスになる。共変性は実型引数の継承関係をそのままジェネリッククラスの継承関係にシフトするが、反変性ではこれを逆にする。共変性では<code>List<猫></code>は<code>List<動物></code>のサブクラスだが、反変性では<code>List<動物></code>は<code>List<猫></code>のサブクラスになる。[[共変性と反変性 (計算機科学)|共変性と反変性]]はまとめてバリアンス(''variance'')と呼ばれる事がある。 |
||
;型制約 |
;型制約 |
||
:(''type constraint'')は、(A)ジェネリッククラスの型引数/型変数、(B)代入値の型が実行時に決められる動的束縛型の変数、(C)動的ローディング時に詳細が隠されたままの値が代入される不透明型の変数、などの宣言に用いられるものである。それぞれは制約用の基準クラスで記号修飾され、その基準クラス及びその派生型の値が代入、束縛、適用されるという宣言になる。(A)の型引数/型変数では基準クラス及びその派生クラスが適用される宣言になる。(B)の動的束縛型では基準クラス及びその派生型の値が代入される宣言になる。(C)の不透明型では基準クラス及びその詳細不明である派生型の値が代入される宣言になる。型制約は型境界(''type bound'')とも呼ばれる。これには上限と下限がある。型制約と上限型境界(''upper type bound'')は性質的に同義である。下限型境界(''lower type bound'')は、基準クラス及びその基底型の値が代入、束縛、適用されるという宣言になる。 |
:(''type constraint'')は、(A)ジェネリッククラスの型引数/型変数、(B)代入値の型が実行時に決められる動的束縛型の変数、(C)動的ローディング時に詳細が隠されたままの値が代入される不透明型の変数、などの宣言に用いられるものである。それぞれは制約用の基準クラスで記号修飾され、その基準クラス及びその派生型の値が代入、束縛、適用されるという宣言になる。(A)の型引数/型変数では基準クラス及びその派生クラスが適用される宣言になる。(B)の動的束縛型では基準クラス及びその派生型の値が代入される宣言になる。(C)の不透明型では基準クラス及びその詳細不明である派生型の値が代入される宣言になる。型制約は型境界(''type bound'')とも呼ばれる。これには上限と下限がある。型制約と上限型境界(''upper type bound'')は性質的に同義である。下限型境界(''lower type bound'')は、基準クラス及びその基底型の値が代入、束縛、適用されるという宣言になる。 |
2021年1月20日 (水) 12:15時点における版
プログラミング・パラダイム |
---|
オブジェクト指向プログラミング(オブジェクトしこうプログラミング、英: object-oriented programming、略語:OOP)とは、互いに密接な関連性を持つデータとメソッドをひとつにまとめてオブジェクトとし、それぞれ異なる性質と役割を持たせたオブジェクトの様々な定義と、それらオブジェクトを相互に作用させる様々なプロセスの設定を通して、プログラム全体を構築するソフトウェア開発手法である。
オブジェクト指向という用語自体は、計算機科学者アラン・ケイによって生み出されている。1962年公開の言語「Simula」にインスパイアされたケイが咄嗟に口にしたとされるこの造語は、彼が1972年から開発公開を始めた「Smalltalk」の言語設計を説明する中で発信されて1981年頃から知名度を得た。しかしケイが示したオブジェクト指向の要点であるメッセージパッシングの考え方はさほど認知される事はなく、代わりにクラスとオブジェクトという仕組みを注目させるだけに留まっている。同時にケイの手から離れたオブジェクト指向は抽象データ型を中心にした解釈へと推移していき、1983年に計算機科学者ビャーネ・ストロヴストルップが公開した「C++」が好評を博したことで、オブジェクト指向に対する世間の理解は「C++」とそのモデルの「Simula 67」のスタイルで定着した。それに基づいてカプセル化、継承、ポリモーフィズムといった考え方も後年に確立された。
特徴
オブジェクト指向プログラミングは、1974年に計算機科学者バーバラ・リスコフらが提唱した抽象データ型を基礎的な考え方にする方向性で定着している。抽象データ型のプログラム実装スタイルを具体的に規定したものが1 - 3であり、日本では一般に三大要素と呼ばれている。これに沿った言語仕様を備えたプログラミング言語がオブジェクト指向準拠と判別されている。4はアラン・ケイが重視する元祖的なコンセプトであり、オブジェクト指向の源流思想として蛇足ながら紹介を加える。
- カプセル化(encapsulation)
- 継承(inheritance)
- ポリモーフィズム(polymorphism)
- メッセージパッシング(message passing)
カプセル化
一定の関連性を持つデータ(変数、プロパティ、フィールド、属性)と、それらを操作するメソッド(関数)をひとまとめにしてオブジェクトとし、外部に対して必要とされるデータとメソッドのみを公開し、それ以外を内部に隠蔽する仕組みがカプセル化と呼ばれる。公開されたデータは外部のメソッドから直接参照または変更する事ができる。公開されたメソッドは外部のメソッドから直接呼び出す事ができる。隠蔽されたデータとメソッドは外部からアクセスされないことが保証され、これは情報隠蔽と呼ばれる。メソッドを通してデータを参照または変更する仕組みはデータの抽象化を表現し、これはデータ抽象と呼ばれる。データを参照するメソッドはゲッターまたはアクセッサと呼ばれる。データを変更するメソッドはセッターまたはミューテイタと呼ばれる。
継承
既存オブジェクトのデータ構成とメソッド構成を引き継いで、新しい派生オブジェクトを定義する仕組みが継承と呼ばれる。引き継ぐ際には新たなデータとメソッドを自由に追加できるので、派生オブジェクトの構成は既存要素+追加要素になる。ここでの既存オブジェクトは基底オブジェクトと読み替えられる。基底は親、派生は子とも読み替えられる。継承が重視されるオブジェクトは、型として用いられるクラスであることが多い。クラスベースでは基底をスーパークラス、派生をサブクラスと呼ぶ。一つのスーパークラスを継承するのは単一継承と呼ばれる。複数のスーパークラスを継承してそれぞれの要素を引き継ぐのは多重継承と呼ばれる。UMLでは汎化と特化の関係で表現されている。メソッドの抽象化に焦点を当てた継承の方は実装継承などと呼ばれる。UMLでは実現と実装の関係で表現されている。実装継承は特定のオブジェクトたちに共通した振る舞い側面を抜き出して抽象化する仕組みを指し、その抽象オブジェクトはインターフェース、トレイト、プロトコルなどと呼ばれる。
ポリモーフィズム
異なる種類のオブジェクトに同一の操作インターフェースを持たせる仕組みがポリモーフィズム(多態性)と呼ばれる。オブジェクト指向下のポリモーフィズムは、クラスの派生関係またはオブジェクトの動的バインディング機能によって、コンパイル時のメソッド名から呼び出されるプロセス内容が実行時に決定されるという仕組みの振る舞いサブタイピングを指す。これはサブタイプ多相の一種である。その代表格は仮想関数であり、オブジェクト指向でポリモーフィズムと言えばこれを指して説明されることが多い。仮想関数は、メソッドが所属するクラスの派生関係のみに焦点を当てた一重ディスパッチであり、スーパークラス抽象メソッドの呼び出しを、それをオーバーライドしたサブクラス実装メソッドの呼び出しにつなげる機能である。一重ディスパッチとはプロセス選択に関与するオブジェクトが一つであることを意味しており、二つ以上の場合は多重ディスパッチになる。多重の方はメソッドが属するクラスの派生関係だけでなく、そのメソッドの各引数のクラスの派生関係にも注目した形態であり、各引数は実行時の型判別とダウンキャストされて、その引数型の組み合わせに対応したプロセスを選択する。一重ディスパッチと多重ディスパッチは動的ディスパッチという分類用語に包括されており、仮想関数はクラスベース向けに特化された動的ディスパッチとも定義されている。クラス機構の代わりにプロトタイプ機構を用いるプロトタイプベースの方では、オブジェクト(フレーム)のメソッド名スロットに当てはめられるメソッド実装の参照が随時切り替えられることにより、そのメソッド名から呼び出されるプロセスが実行時に決定されるという仕組みで広義の振る舞いサブタイピングを表現している。この仕組みも動的ディスパッチという分類用語に包括されており、便宜的にそのまま動的ディスパッチと呼ばれることが多い。
メッセージパッシング
I thought of objects being like biological cells and/or individual computers on a network, only able to communicate with messages.
(さながら生物の細胞、もしくはネットワーク上の銘々のコンピュータ、それらはただメッセージによって繋がり合う存在、僕はオブジェクトをそう考えている) — Alan Kay
... each object could have several algebras associated with it, and there could be families of these, and that these would be very very useful.
(銘々のオブジェクトは関連付けられた幾つかの「代数」を持つ、またそれらの系統群も持つかもしれない、それらは極めて有用になるだろう) — Alan Kay
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.
(日本語には「間」という言葉がある・・・成長的なシステムを作る鍵とは内部の特徴と動作がどうあるべきかよりも、それらがどう繋がり合うかをデザインする事なんだ) — Alan Kay
I wanted to get rid of data. ... I realized that the cell/whole-computer metaphor would get rid of data, ...
(僕はデータを取り除きたかった。・・・僕は気付いた、細胞であり全体でもあるコンピュータメタファはデータを除去するであろうと、) — Alan Kay
歴史
1954年に初の高水準言語・FORTRANが登場すると、開発効率の劇的な向上と共にソフトウェア要求度も自然と高まりを見せてプログラム規模の急速な拡大が始まった。それに対応するために肥大化したメインルーチンをサブルーチンに分割する手法と、スパゲティ化したgoto命令を制御構造文に置き換える手法が編み出され、これらは1960年に公開された言語「ALGOL60」で形式化された。当時のALGOLはアルゴリズム記述の一つの模範形と見なされたが、それと並行して北欧を中心にした計算機科学者たちはより大局的な観点によるプログラム開発技法の研究を進めていた。
Simulaの開発(1962 - 72)
1962年、ノルウェー計算センターでモンテカルロ法シミュレーションを運用していた計算機科学者クリステン・ニゴールは、ALGOL60を土台にしてProcessと呼ばれるコルーチン機構を加えたプログラミング言語「Simula」を公開し、続けてその拡張にも取り組んだ。ニゴールの同僚で、1963年にSimulaを汎用機UNIVAC系統上で運用できるように実装した計算機科学者オルヨハン・ダールは、Processにローカル変数構造を共有する複数の手続き(サブルーチン)を加えてパッケージ化する言語仕様を考案した。程なくしてALGOL60コンパイラに準拠していての限界を悟ったニゴールとダールは、1965年からSimulaを一から再設計するように方針転換した。その過程で彼らは、計算機科学者アントニー・ホーアが考案して1962年のSIMSCRIPT(FORTRAN用のスクリプト)に実装していたRecord Classを参考にしている。Record Classはソースコード水準の抽象表現を、各汎用機に準拠したマシンコード水準の実装符号に落とし込む段階的データ構造のプログラム概念であった。これをモデルにした継承とその構造上に成り立つ仮想手続き(仮想関数)の仕組みも考案され、この両機能を備えたProcessのパッケージ化を「クラス」とし、クラスをメモリに展開したものを「オブジェクト」とする言語仕様がまとまり、1967年に「Simula67」が初公開された。オブジェクトという用語は、MITの計算機科学者アイバン・サザランドが1963年に開発したSketchpad(CADとGUIの元祖)の設計内にあるObjectが先例であった。Simula67コンパイラはまずUNIVAC上で運用され、翌年から汎用機バロースB5500などでも稼働されて北欧、ドイツ、ソ連の各研究機関へと広まり、1972年にはIBM汎用機System/360などにも導入されて北米全土にも広まった。その主な用途は物理シミュレーションであった。
構造化プログラミングの提唱(1969 - 75)
Simulaの普及と前後して1960年代半ばになると、プログラム規模の際限ない肥大化に伴う開発現場の負担増大が顕著になり、いわゆるソフトウェア危機問題が計算機科学分野全般で取り沙汰されるようになった。その解決に取り組んだ計算機科学者エドガー・ダイクストラは、1969年のNATOソフトウェア工学会議で「構造化プログラミング」という論文を発表しトップダウン設計、段階的な抽象化、階層的なモジュール化、共同詳細化(抽象データ構造と抽象ステートメントのjoint)といった構造化手法を提唱した。ダイクストラの言う構造化とは開発効率を高めるための分割統治法を意味していた。なおこの構造化プログラミングは後に曲解されて制御構造文を中心にした解釈の方で世間に広まり定着している。共同詳細化は抽象データ構造を専用ステートメントを通して扱うという概念である。これはSimulaの手続きを通してクラス内の変数にアクセスするという仕組みをモチーフにしていた。段階的な抽象化と階層的なモジュール化は時系列的にも、SIMSCRIPTの段階的データ構造と、Simura67の継承による階層的クラス構造を模倣したものであった。ダイクストラ、ホーア、ダールの三名は1972年に『構造化プログラミング』と題した共著を上梓していることから互いの研鑽関係が証明されている。その階層的プログラム構造という章の中でダールは、Simulaの目指した設計を更に明らかにした。
1974年にMITの計算機科学者バーバラ・リスコフは「抽象データ型」というプログラム概念を提唱し、ダイクストラが提示したモジュールの共同詳細化を、その振る舞いによって意味内容が定義される抽象データという考え方でより明解に形式化した。一方、1970年に構造化言語Pascalを開発していた計算機科学者ニクラウス・ヴィルトは、ダイクストラによる共著出版後の1975年にモジュール化言語Modulaを提示してモジューラプログラミングというパラダイムを生み出している。このようにいささか奇妙ではあるが、Simulaのクラスとオブジェクトというプログラム概念は、巷で言われる構造化からモジュール化へといった進化の流れとは関係なく、しかもその前段階においてさながら彗星のように生まれたパラダイムであった。
Smalltalkとオブジェクト指向の誕生(1972 - 81)
Simula発のProcessとクラスの仕様は、パロアルト研究所の計算機科学者アラン・ケイによるオブジェクト重視と「メッセージング」という考え方のヒントになった。ケイはプログラム内のあらゆる要素をオブジェクトとして扱い、オブジェクトはメッセージの送受信でコミュニケーションするという独特のプログラム理論を提唱した。それには関数適用風の書式を用いたオブジェクト同士の多種多様なデリゲーションと、プログラムコードとしても解釈できるデータ列を送信してそれを評価(eval)することで新たなデータを導出できるなどのアイディアが盛り込まれていた。オブジェクトが送るか受け取ったメッセージは任意のタイミングで評価できるので非同期通信や単方向通信をも可能にしていた。この発想の背景にはLISPの影響があった。オブジェクトとメッセージングの構想に基づいて開発された「Smalltalk」はプログラミング言語とGUI運用環境を併せたものとなり、1972年にゼロックスAlto上で初稼働された。Smalltalkの設計を説明するためにケイが考案した「オブジェクト指向」という用語はここで初めて発信された。またケイのメッセージング構想はMITの計算機科学者カール・ヒューイットに能動的なプロセス代数を意識させて、1973年発表のアクターモデルのヒントにもなっている。しかしデリゲーションの多用とデータ列が常にコード候補として扱われる処理系は、当時のコンピュータには負荷が大きく実用的な速度を得られないという問題にすぐ直面した。Smalltalk-74とSmalltalk-76の過程で、やむなくメッセージは構想時の柔軟さが失われるほどシステム向けに最適化され、レシーバーはセレクタパターン重視のメソッド化が進み、オブジェクトは静的なクラス定義の存在感が大きくなった。
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".
(Smalltalkはその構文やライブラリやクラスをも関心にしていないという事だけではない。多くの人の関心を小さなアイディアに向かせたことから、僕はオブジェクトという用語を昔作り出したことを残念に思っている。大切なのはメッセージングなんだ。) — Alan Kay
1980年のSmalltalk-80は、元々はメッセージを重視していたケイを自嘲させるほど同期的で双方向的で手続き的なオブジェクト指向へと変貌していた。それでも動的ディスパッチと委譲でオブジェクトを連携させるスタイルは画期的であり、1994年に発表されるデザインパターンの模範にもされている。1981年に当時の著名なマイコン専門誌『BYTE』がSmalltalkとケイ提唱のオブジェクト指向を紹介して世間の注目を集める契機になったが、ケイの思惑に反して技術的関心を集めたのはクラス機構の方であった。オブジェクト指向は知名度を得るのと同時に、Simula発のクラスとそれを理論面から形式化した抽象データ型を中心に解釈されるようになり、それらの考案者がケイの構想とは無関係であったことから、オブジェクト指向の定義はケイの手を離れて独り歩きするようになった。
C++の開発(1979 - 88)
Simulaを研究対象にしていたAT&Tベル研究所の計算機科学者ビャーネ・ストロヴストルップは、1979年からクラス付きC言語の開発に取り組み、1983年に「C++」を公開した。C++で実装されたクラスは、Simula譲りの継承と仮想関数に加えて、レキシカルスコープの概念をクラス定義とその継承構造に応用したアクセスコントロールを備えていた。C++で確立されたアクセスコントロールはカプセル化の元になったがコードスタイル上ほとんどザル化されており、その理由からストロヴストルップ自身もC++は正しくない(not just)オブジェクト指向言語であると明言している。1986年にソフトウェア技術者バートランド・メイヤーが開発した「Eiffel」の方は、正しいオブジェクト指向を標榜してクラスのデータ抽象を遵守させるコードスタイルが導入されていた。クラスメンバ(フィーチャー)は属性、手続き、関数の三種構成で、手続きで属性を変更し関数で属性を参照するという形式に限定されており、これは抽象データ型の振る舞い意味論に沿った実装であった。アクセスコントロールはC++のアクセス修飾子による段階的レキシカルスコープ定義に対して、自身のクライアントクラスを定義する書式になり、これはモジューラプログラミングの情報隠蔽論に沿った実装であった。C++の仮想関数は延期手続き/関数として実装された。
I made up the term ‘object-oriented’, and I can tell you I didn’t have C++ in mind.
(僕はオブジェクト指向という言葉を作ったけど、C++(のような言語)は考えていなかった) — Alan Kay
1986年からACMがオブジェクト指向会議(OOPSLA)を年度開催し、そのプログラミング言語セクションでは抽象データ型の流れを汲むクラス・パラダイムが主要テーマにされ、それを標準化するための数々のトピックが議題に上げられている。モジュール性、情報隠蔽、抽象化、再利用性、階層構造、複合構成、実行時多態、動的束縛、総称型、自動メモリ管理といったものがそうであり、参画した識者たちによる寄稿、出版、講演を通して世間にも広められた。そうした潮流の中でストロヴストルップはデータ抽象の重要性を訴え、リスコフは基底と派生に分けたデータ抽象の階層構造の連結関係について提言した。契約による設計を提唱するメイヤーが1988年に刊行した『オブジェクト指向ソフトウェア構築』は名著とされ、Eiffelを現行の模範形とする声も多く上がった。ただしこれは学術寄りの意見でもあったようで、世間のプログラマの間では厳格なEiffelよりも柔軟で融通の利くC++の人気の方が高まっていた。また、Smalltalk発のメッセージ・メタファを重視しようとする流れの中で、クラスのメソッド呼び出しをオブジェクトにメッセージを送ることになぞらえる考え方が広まった。これは実行時の選択メソッドをメッセージの発送先にする意味合いで、動的/一重/多重ディスパッチの呼称の由来になっている。他方でSmalltalkの仕様に忠実であろうとする動きもあり、1984年に計算機科学者ブラッド・コックスが開発した「Objective-C」はSmalltalkをモデルにしてそれを平易化した言語であった。そのメッセージレシーバーはメソッドリストにないセレクタを受け取った場合にのみ動的ディスパッチ機構に移るというスタイルで形式化された。メッセージレシーバの仕組みは遠隔手続き呼出し/オブジェクト要求ブローカーの実装に適していたので分散システムとオブジェクト指向の親和性を認識させることになった。
プロトタイプベースの考案(1985 - 90)
Smalltalkのオブジェクト指向はアラン・ケイがその影響を言及していたLISPコミュニティを感化して、Smalltalkが示した万物をオブジェクトとして扱うメタオブジェクトプロトコルをLISPプログラミングに融合させようとする潮流を生みだした。これはLISPの基礎情報要素であるシンボル型の集合体となるオブジェクトを構築し、シンボル型であるメンバ変数名/メンバ関数名を実行時にその都度評価(eval)してその変数実体の参照/関数実体の呼出につなげるという構想から、フレームと呼ばれるデータ構造体のスロットに変数ポインタ/関数ポインタを付け替えするという実装などにまとめられた。シンボル型がマッピングされるスロットは増設削減でき、実例元クラスと継承元クラス用のスロットも加えられた。これらは機能名としてはメタクラスと呼ばれた。これらのメタオブジェクトプロトコルを導入して、1985年にMIT人工知能研究所のLISPマシン上で「Flavors」が実装された。スロットにマッピングされたシンボル型の判別による動的型付けのダックタイピングの概念が生まれ、またシンボル型のマッピング構成を部品化して多重継承させるというミックスインの機能も考案された。1988年にFlavorsの言語機能をCommon Lispに融合させた「CLOS」が公開されたが、こちらは関数を中心にして抽象データ型から距離を置いたスタイルになった。FlavorsおよびCLOSの発表と並行してパロアルト研究所では、計算機科学者デビッド・アンガーがSmalltalkの方言として制作する「Self」を1987年に初回稼働して1990年に一般公開した。Selfに導入されたメタオブジェクトプロトコルは、後にプロトタイプベースまたはインスタンスベースと呼ばれるパラダイムに発展する。同時にそれと、従来のクラス機構を中心にしたオブジェクト指向言語を区別するためのクラスベースという言葉も生まれた。
コンポーネントとネットワーク(1989 - 97)
ネットワーク技術の発展に連れて、データとメソッドの複合体であるオブジェクトの概念は、分散システム構築のための基礎要素としての適性を特に見出される事になり、IBM社、アップル社、サン社などが1989年に共同設立したOMGは、企業システムネットワーク向け分散オブジェクトプログラミングの標準規格となるCORBAを1991年に公開した。その前年にマイクロソフト社はウェブアプリケーション向けの分散オブジェクト技術となるOLEを発表し、1993年にはCOMと称するソフトウェアコンポーネント仕様へと整備した。このCOMの利用を眼目にしてリリースされた「Visual C++」「Visual Basic」はウェブ時代の新しいプログラミングスタイルを普及させる先駆になった。この頃に抽象データ型のメソッドを通したデータ抽象、データ隠蔽、アクセスコントロールおよび分散オブジェクト=プロセス間通信のインターフェース機構によるプログラムの抽象化といった概念は、カプセル化という用語にまとめられるようになった。クラスの継承が最もオブジェクト指向らしい機能と見なされていたのが当時の特徴であった。継承構造を利用したサプタイピングは多態性という用語に包括され、多重継承の欠点が指摘されると分散オブジェクトのそれに倣ったインターフェースの多重実装設計が取り上げられた。こうしてカプセル化の誕生と連動するようにしていわゆるオブジェクト指向の三大要素がやや漠然と確立されている。1996年にサン社がリリースした「Java」は三大要素が強く意識されたクラスベースであり、その中の分散オブジェクト技術はBeansと呼ばれた。類似の技術としてアップル社もMacOS上でObjective-Cなどから扱えるCocoaを開発している。また、1994年から96年にかけて「Python」「Ruby」「JavaScript」といったオブジェクト指向スクリプト言語がリリースされ、プロトタイプベースという新しいプログラミングスタイルを定着させている。1994年のGOFデザインパターンの発表と、1997年にOMGが標準モデリング言語として採用したUMLは、オブジェクト指向プログラミングの標準化を促進させた。
... 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.
(Simulaを触媒にした二本の道があった。最初の一本はバイオネットな非データ手法で僕が選んだ方。少し遅れたもう一本は抽象データ型、こっちの方がずっと賑わっている。) — Alan Kay
代表的なオブジェクト指向言語
オブジェクト指向言語は、抽象データ型に準拠したクラスベース、メタオブジェクトプロトコルを採用したプロトタイプベース、Smalltalkを規範にしたメッセージングベースの三タイプに分類されるのが一般的である。クラスベースでは「C++」「Java」「C#」が代表的である。プロトタイプベースでは「Python」「JavaScript」「Ruby」が有名である。メッセージングベースでは「Smalltalk」「Objective-C」「Self」などがある。言語仕様の中でオブジェクト指向の存在感が比較的高い代表的なプログラミング言語は以下の通りである。
- 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の方言として開発された。それ故にプロトタイプからプロトタイプを派生させ、またインスタンスを複製してそれにプロパティとメソッドを動的バインディングできるというメタオブジェクトプロトコルも忠実に実装された。プロトタイプベースというパラダイムはこのSelfから認知されるようになった。動的型付け重視である。Smalltalkと同様に専用のランタイム環境上で実行され、GUI運用環境の構築も目標にしていた。Selfのランタイム環境は実行時コンパイラ機能を初めて実装したことで知られており画期的な処理速度を実現している。この技術はJava仮想マシンの土台になった。
- Common Lisp(CLOS) 1988年(ANSI規格化は1994年)
- クラスベースのオブジェクト指向。メソッド記述の関数呼び出し形式への統合、多重ディスパッチ、クラスの動的な再定義等を特徴とする。
- 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# 2000年
- Javaを強く意識してマイクロソフト社が開発したクラスベースのオブジェクト指向言語。Javaよりもマルチパラダイムの性質が強化されており、言語仕様も比較的大規模と言える。ステートメント書式と各種データ型の取り扱いに、C++風の柔軟性と融通的を残しながら様々な糖衣構文サポートも加えてコーディング上の利便性がより高められている。マルチスレッド仕様も整備されている。アドホック多相では拡張メソッド、インデクサ、演算子オーバーロードなどを備えている。パラメトリック多相では共変/反変も扱えるジェネリクスを備えている。サブタイプ多相はクラスは単一継承でインターフェースは多重実装と基本通りである。関数型構文も整備されており、特にメソッド参照機能であるデリゲートの有用性が高められている。デリゲートはイベント駆動構文の平易な表現も可能にしている。基本は静的型付けであるが、動的束縛型とダックタイピングによる動的型付けの存在感が高められているので漸進的型付けの言語と見なされている。.NET Framework(共通言語基盤=仮想実行システム)上で実行される。
- Scala 2003年
- クラスベースのオブジェクト指向と関数型プログラミングを融合させた言語。クラス機構と関数型の型システムに同等の比重が置かれており静的型付け重視である。ミックスイン相当のトレイトと、共変/反変および抽象タイプメンバを扱えるジェネリクスを連携させた多態性が重視されておりオブジェクトを様々に派生型付けできる。シングルトンオブジェクトの役割が形式化されて従来のクラス静的メンバの新解釈にも用いられている。専用の定義書式によりイミュータブルなオブジェクトが重視されている。上述の派生型付けスタイルとオブジェクト引数の抽出構文とパターンマッチング式の併用連鎖計算はモナドを彷彿とさせて独特の関数型スタイルを表現できる。Java仮想マシン上で動作するJavaテクノロジ互換言語である。
- Kotlin 2011年
- 静的型付けのクラスベースのオブジェクト指向であるが、手続き型プログラミングに回帰しており、クラス枠外の関数とグローバル変数の存在感が高められている。クラスはpublicアクセスとfinal継承がデフォルトにされて、カプセル化と継承が公然と軽視されている。これによりインスタンスは手続き型の関数の対象値としての役割が強められ、その操作をサポートする関数型構文も導入されている。仮想関数と抽象クラスによる多態性は標準通りである。Java仮想マシン上で動作するJavaテクノロジ互換言語である。
- TypeScript 2012年
- JavaScriptを強く意識してマイクロソフト社が開発したオブジェクト指向スクリプト言語。JavaScriptのプログラムを静的型付けで補完した言語である。クラスベース向けの構文と、関数型プログラミングの型システムのスタイルが加えられている。特に後者の性質が強調されている事から静的型付け重視である。継承構造によるサブタイプ多相はほぼ除外されており、ジェネリクスと型アノテーションでオブジェクトを扱うというパラメトリック多相とアドホック多相を重視するデザインになっている。オブジェクト指向ではあるが関数型の性格が強めである。
- Swift 2014年
- Objective-Cを発展させたものであるが、メッセージ構文は破棄されており、クラスベースのオブジェクト指向になっている。オブジェクトのイミュータブル性重視の構文が採用されている。プロテクト可視性の削除によってクラスの縦並びの継承は軽視されており、プロトコルの横並びの多重実装を重視している。プロトコルはインターフェースとミックスインの中間的機能であり、インスタンスはプロトコルを基準にして型分類され、また抽象化される。プロトコルとジェネリクスの連携による多態性が重視されている。モジュールの動的ローディングは不透明型の仕組みで補完されている。静的型付け重視である。
用語と解説
- クラス
- (class)の仕組みを中心にしたオブジェクト指向をクラスベースと言う。クラスはデータメンバとメソッドをまとめたものであり、操作的意味論を付加された静的レコードとも解釈される。クラスはインスタンスのひな型であり、インスタンスはクラスを実例化(量化)したものである。クラスはカプセル化、継承、多態性の三機能を備えていることが求められている。カプセル化はデータメンバとメソッドの可視性を指定する機能である。継承は自身のスーパークラスを指定する機能である。多態性はオーバーライドと仮想関数テーブルを処理する機能である。コンストラクタとデストラクタの実装も必要とされている。前者はインスタンス生成時に、後者はインスタンス破棄時に呼び出されるメソッドである。
- プロトタイプ
- (prototype)の仕組みを中心にしたオブジェクト指向をプロトタイプベースと言う。プロトタイプとは識別名&中間参照ペアの集合体を指す。この集合体は一般にフレームと呼ばれる。識別名&中間参照ペアの割り当て箇所は一般にスロットと呼ばれる。スロットにはデータメンバとメソッドの識別名&中間参照ペアが代入されるので、プロトタイプはクラスと同様にデータメンバとメソッドをまとめたものになる。プロトタイプは言語によってはクラスと呼ばれている。プログラマはシステムが提供する基底プロトタイプに、自由にデータメンバとメソッドを付け足して任意の派生プロトタイプを作成できる。プロトタイプは「型」相当であり、それを複製する方式で生成されるインスタンスは「値」相当である。データメンバとメソッドはその参照にインスタンスを必要とするものと、しないものに分かれる。前者はインスタンスメンバ、後者は静的メンバに相当するものである。インスタンスにも自由にデータメンバとメソッドを付け足すことができる。インスタンスはそのプロトタイプへの参照を保持しており、プロトタイプはその親プロトタイプへの参照を保持している。これは継承相当の機能になっている。インスタンスへの自由なメンバ付け替えは多態性相当の機能になっている。ただしプロトタイプは動的な関数型言語由来の仕様なので、クラスを用いるOOPの三大要素とはまた違った視点から眺める必要がある。
- メッセージ
- オブジェクト指向で言われるメッセージ(message)は、複数方面の考え方が混同されている曖昧な用語になっている。元々はSmalltalkから始まったメッセージングベースのオブジェクト指向の中心メカニズムである。以前はクラスベースの方でもメソッドの呼び出しをメッセージを送るという具合に考えることが推奨されていた。メッセージはオブジェクトのコミュニケーション手段と標榜されているが、その忠実な実装内容はそれほど知られていないのが実情である。最も混同されているものにアクターモデルがあるが、そこで言われる非同期性とオブジェクト指向で言われる遅延性は現行の実装スタイルではそれほど共通していない。リモートプロシージャコールとオブジェクトリクエストブローカーの働き方もメッセージパッシングと呼ばれることが多いが、その仕様と機能は動的ディスパッチに該当するものである。メッセージのオブジェクト指向的運用はメッセージングと名付けられているが、普通にメッセージパッシングとも呼ばれている。具体的な機能例としてはSmalltalk、Objective-C、Selfのメッセージレシーバーと、Rubyのメソッドミッシングなどがある。ただしこれらはアラン・ケイのメッセージング構想の忠実な再現にまでは到っていない。
- インスタンス
- (instance)はクラスベースではクラスを実例化(量化)したものであり、実装レベルで言うとデータメンバ群と仮想関数テーブルをメモリ上に展開したものになる。プロトタイプベースではプロトタイプを複製する方式で生成されたオブジェクトを指す。実装レベルで言うとメモリ上に展開された識別名&中間参照ペアの動的配列になる。
- データメンバ
- (data member)はクラスまたはオブジェクトに属する変数。言語によってフィールド、プロパティ、メンバ変数、属性と呼ばれる。データメンバは、クラスデータメンバとインスタンスデータメンバに分かれる。クラスデータメンバは静的データメンバとも呼ばれる。その中で定数化されたものはクラス定数と呼ばれる。クラスデータメンバはクラス名の名前空間でスコープされたグローバル変数と同じものであり、プログラム開始時から終了時まで確保される。インスタンスデータメンバはインスタンス生成時にメモリ上に確保されるものであり、その破棄時に消滅する。インスタンスデータメンバの参照にはそのthis参照が必要である。プロトタイプベースでは、プロトタイプで定義されたデータメンバでそのアクセスにインスタンス(self)を必要としないものが静的データメンバになる。
- メソッド
- (method)はクラスまたはオブジェクトに属する関数。言語によってはメンバ関数とも呼ばれる。データメンバの参照に特化したものはゲッター(getter)アクセッサ(accessor)と呼ばれる。データメンバの変更に特化したものはセッター(setter)ミューテイタ(mutator)と呼ばれる。メソッドは、クラスメソッドとインスタンスメソッドに分かれる。クラスメソッドは静的メソッドとも呼ばれる。クラスメソッドはクラス名の名前空間でスコープされたグローバル関数と同じものである。インスタンスメソッドを呼び出すにはそのthis参照が必要である。プロトタイプベースでは、プロトタイプで定義されたメソッドでそのアクセスにインスタンス(self)を必要としないものが静的メソッドになる。
- コンストラクタ
- (constructor)はインスタンス生成時に呼び出されるそのクラスのメソッドである。インスタンスデータメンバを任意の値で初期化するためのものであるが、その他の初期化コードも記述できる。プロトタイプベースではシステム提供プロトタイプが保持する生成用メソッドまたは生成用のグローバル関数がコンストラクタ相当になる。
- デストラクタ
- (destructor)はインスタンス破棄時に呼び出されるそのクラスのメソッドである。インスタンス破棄の影響を解決する任意の後始末コードを記述できる。インスタンスの破棄は占有メモリの解放を意味する。なお、ガーベジコレクタ実装言語ではファイナライザになっている事がある。プログラマが呼び出すデストラクタの方はその終了がメモリ解放に直結しているのに対し、ガーベジコレクタが呼び出すファイナライザの方はそうではない。
- 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クラスはひとつにまとめられる事になる。同時に一度辿ったクラスは省略される事にもなる。
- MRO
- メソッド解決順序(method resolution order)は、多重継承時の親クラスの巡回順序を定義するものである。参照されたメソッドが自クラスにない場合はその親クラスを巡回してサーチされる。メソッドはクラスメンバと読み替えてもよい。これは深さ優先検索(deep-first)と幅優先検索(breadth-first)に分かれるが、オブジェクトの構造概念から深さ優先の方が自然とされている。従って一般的な多重継承では深さ優先検索が用いられて親クラスの重複は仮想継承で解決されている。しかし詳細は割愛するが、仮想継承部分の巡回順序に不自然さを指摘する意見もあったので、これを解決するために深さ優先と幅優先をミックスしたC3線形化(C3 linearization)というメソッド解決順序が考案された。C3線形化では親クラスの重複部分に対してのみ幅優先検索を適用することで、仮想継承を用いることなく菱形継承問題も自然に解決されている。
- 抽象クラス
- (abstract class)は、全部または一部のメソッドが抽象化されているクラスを意味する。抽象化されたメソッドとは、メソッドシグネチャ(返り値+メソッド名+引数欄)だけが定義されてコード内容が省略されているメソッドを指す。抽象クラスはインスタンス化できないので継承専用になる。抽象メソッドは、そのサブクラスの方でメソッドのコード内容が実装されてオーバーライドされる。
型システム |
---|
主要カテゴリ |
静的型付け vs 動的型付け 強い vs 弱い 明示的 vs 型推論 名前的 vs 構造的 ダックタイピング |
マイナーカテゴリ |
部分型 再帰型 部分構造型 依存型 漸進的型付け フロータイピング 潜在的型付け |
型理論のコンセプト |
直積型 - 直和型 交差型 - 共用型 単一型 - 選択型 帰納型 - 精製型 トップ型 - ボトム型 函数型 - 商型 全称型 - 存在型 一意型 - 線形型 |
- インターフェース
- (interface)はプログラム概念と機能名の双方を指す用語である。言語によってはプロトコルと言われる。抽象メソッドと実体メソッドをメンバにする純粋抽象〜半抽象クラスを意味する。一般的にデータメンバはメンバにされない。クラスの振る舞い側面を抜き出した抽象体である。クラスによるインターフェースの継承は実装と呼ばれる。多重実装可が普通である。ミックスインとの違いは、抽象階層に焦点が当てられている事であり、直下の実装オブジェクトを共通の振る舞い側面でまとめることがその役割である。インターフェースは自身の下位概念である実装継承オブジェクトをグループ化できる。記名的型付けに準拠しているのでインターフェースの実装の明記が振る舞い側面の識別基準になる。インターフェースは抽象メソッド主体なので多重継承時のメンバ名の重複はあまり問題にならない。共通の実装メソッドに集約されるからである。インターフェースは非インスタンス対象である。
- ミックスイン
- (mixin)はインターフェースに似たプログラム概念を指す用語である。機能名は言語によってトレイト、プロトコル、構造型(structural type)と言われる。抽象メソッドと実体メソッドとデータメンバをメンバにする継承専用クラスを意味する。クラスを特徴付けるための構成パーツである。クラスによるトレイトの継承は実装と呼ばれる。多重実装可が普通である。インターフェースとの違いは、トレイトの実装階層に焦点が当てられている事であり、オブジェクトを所有メンバで特定してまとめることがその役割である。トレイトは自身の上位集合である実装継承オブジェクトをグループ化できる。構造的型付けに準拠しているので所属メンバ構成自体がトレイト等価性の識別基準になる。これはトレイト実装を明記していなくても、そのトレイトが内包する全メンバを所持していれば同じトレイトと見なされることを意味する。トレイトは合成や交差が可能である。トレイトは多重継承時のメンバ名重複の際にその参照の優先順位に注意する必要がある。トレイトは非インスタンス対象である。
- 型イントロスペクション
- (type introspection)は一般に実行時型チェックと呼ばれるものである。プログラマが認知できない形でコンパイラまたはインタプリタが別途実装しているインスタンスの型情報を、実行時にその都度参照してインスタンスの型を判別する仕組みである。静的型付け下では専用の実行時型チェック構文(instanceofやdynamic_cast)によって型判別し、ダウンキャストなどに繋げられる。動的型付け下では変数への再代入時や関数への引数適用時にランタイムシステムが自動的に型判別し、多重ディスパッチなどに繋げられる。型イントロスペクションでは型情報のタグ識別子が判定基準になっているので記名的型付けの考え方に準じている。
- ダックタイピング
- (duck typing)は、特定のメソッド名(メソッドシグネチャ)またはプロパティ名(データメンバ名)の識別子を持っているかどうかでインスタンスをその都度分類する仕組みである。これはその場限りの型判別と言えるものである。判別されたインスタンスは自身が持つとされたメソッドまたはプロパティを呼び出される事になる。動的型付けの機能であり、ダックタイピングでは型情報の構成内容が判定基準になっているので構造的型付けの考え方に準じている。
- 型推論
- オブジェクト指向下の型推論(type inference)は、型宣言ないし型注釈を省略して定義された変数の「型」が自動的に導き出される機能を指す。型はクラスと同義である。静的型付けの機能であり、コンパイラまたはインタプリタがソースコードをあらかじめ解析し、初期値の代入を始めとしたその変数の扱われ方によって型を導き出す。ここで導き出される「型」とは他の変数への代入可能性や、関数の引数への適用可能性といったあくまで等価性の基準で決められるので、プログラマが人為的な意味付けによる型定義を重視している場合は予期せぬ結果が発生することにもなる。型推論は推論的型付けとも呼ばれ、普通に型宣言と型注釈を用いる明示的型付けの対極に位置付けられるが、昨今のオブジェクト指向言語では双方を併用するのが主流になっている。
- メタクラス
- (metaclass)はメタオブジェクトプロトコルに準拠した機能名であり、実装方式は言語毎に違いがある。メタクラスは、クラスのデータメンバ、メソッド、スーパークラス、内部クラスなどの定義情報を記録したメタデータである。メタクラスのインスタンス(実例化)がクラスになる。クラスベースのメタクラス機能は、実装レベルではシステム側が用意している特別なシングルトンオブジェクトと考えた方が分かりやすい。それにはほとんどの場合システム側が提供する抽象インターフェースを通してのみアクセスできる。メタクラスの情報を参照ないし変更できる機能はリフレクションと呼ばれる。メタクラスの変更はその実例クラスに直ちに反映される。プロトタイプベースのメタクラス機能では、メタクラスもプログラマが自由に扱えるオブジェクトになるので、メタクラスのそのまたメタクラスを定義できる形而上関係も存在し、基底メタクラスと派生メタクラスを定義できる継承関係も存在する。またメタクラス/クラスの実体を指す「eigenclass」といったプログラム概念も存在する。
- リフレクション
- (reflection)は、メタクラスの内容を参照または変更する機能であるが、言語ごとに変更できる内容の範囲は異なっている。データメンバではデータ型、識別子、可視性が変更対象になる。メソッドではリターン型、識別子、パラメータリスト、可視性、仮想指定が変更対象になる。双方の追加定義と削除もできる事がある。スーパークラスも変更できる事がある。また、実行時の文字列(char配列やString)をデータメンバとメソッドの内部識別子として解釈できる機能もリフレクションに当たる。これは実行時の文字列によるデータメンバの参照とメソッドの呼び出しを可能にする。
- メタアノテーション
- (metadata annotation)はクラスに任意の情報を埋め込める機能である。情報とは文字列と数値からなるキーワード、シンボル、テキストである。プログラマが自由な形式で書き込んで随時読み取るものであるが、システムから認識される形式のものもある。実装レベルではメタクラスに書き込まれてリフレクション機能またはその糖衣構文で読み取ることになる。マーカーインターフェースの拡張とも見なされている。メタアノテーションはクラス単位だけでなく、言語によってはインスタンス単位やメソッド単位でも埋め込むことができる。アドホック多相とされる。
- 動的ディスパッチ
- (dynamic dispatch)は、コンパイル時のメソッド名から呼び出されるメソッド内容が実行時に決定される仕組み全般を指す用語である。メソッドに引数を渡しての呼び出しを、オブジェクトにメッセージを発送(ディスパッチ)することになぞらえた事が由来である。発送先は実行時に選択決定されるメソッド内容を指す。メッセージは「this参照×第1引数×第2引数..」といった直積集合で考えられているのでシングル、ダブル、マルチプルといった呼称になっている。発送先はthisおよび各引数の派生関係の組み合わせで選択される。thisの派生関係のみ影響しているものは専ら仮想関数と呼ばれるシングルディスパッチになる。それがthisでなく引数ならばただのシングルになる。thisまたは各引数の内の2個以上のオブジェクトの派生関係が影響しているものはマルチプルディスパッチになる。その中で特にthisと先頭引数の2個が影響して先頭引数インスタンスの仮想関数がthisを引数にしているVisitor形態のものはダブルディスパッチと呼ばれている。
- 動的バインディング
- (dynamic binding)は、識別子が参照するまたは呼び出すオブジェクト、インスタンス、メソッド、データメンバなどのプログラム要素が、コンパイル時ではなく実行時に決められる仕組み全般を指す用語である。識別子はいわゆる変数名や関数名などを指す。
- 遅延バインディング
- (late binding)は、識別子が参照するオブジェクトをコンパイル時に決める事前バインディング(early binding)の対義語であり、この場合は識別子が参照するオブジェクトを実行時に決める動的バインディングと同じ意味で用いられる。また他方では動的バインディングの中で、特に実行コードの動的ローディング機能を通して実装される方を遅延バインディングとする考え方もある。実行コードとはDLLやクラスライブラリやモジュールなどを指しており、それらが内包するクラスやメソッドを専用の不透明型または動的束縛型に代入する。その呼び出しのための内部識別子はコンパイル時には存在していないことが多いので、実行時の文字列(char配列やString)を内部識別子に解釈するためのリフレクション機能が多用されることになる。
- パッケージ
- (package)は1個以上のクラスをまとめたものである。多くなったクラスをグループ化するための仕組みである。パッケージの定義は言語ごとに異なるが、名前空間(namespace)と同等の機能になっているケースが多い。実装レベルではパッケージ名は自動的にクラス名の接頭辞になってクラス名を差別化し、名前衝突を回避している。
- モジュール
- (module)は1個以上のクラスをまとめたものである。パッケージと似ているが、オブジェクト指向下のモジュールはもっぱら動的ローディング(遅延バインディング)と情報隠蔽に焦点を当てたプログラム概念である。情報隠蔽はカプセル化と同様に、自身の内包クラスの外部公開(輸出)と内部隠蔽を定義できる。自身が参照する他モジュールは輸入するという形式で明確に宣言される。動的ローディング用途のモジュールでは内包する基底クラスの詳細を明らかにしつつも、その派生クラスの種類と詳細を明らかにしていないケースが多々あるので、その派生クラスを代入するための動的束縛型は特に不透明型(opaque type)と呼ばれる。不透明型はもっぱら型制約と併せて用いられる。
- モンキーパッチ
- (monkey patch)はモジュールやスクリプトファイルなどの動的ローディングを用いて、インタプリタ実行後またはコンパイル後のソースコード内容を変化させる手法である。ソースコードに特定のフィルター処理を記述しておき、その中で任意の箇所を動的ローディングされたモジュール内のクラスや関数や変数で置き換えさせる事で、その時の配置モジュールに合わせた処理内容の変化ができる。モジュールを外せばフィルター処理は無効になる。この置き換え(パッチ当て)は遅延バインディング相当である。ソースコードを変えなくてよいのが条件である。
- ジェネリクス
- (generics)は、クラスメンバの任意の「型」を総称化したままのクラス定義を可能にし、そのクラスをインスタンス化する各構文箇所で「型」の詳細を決定できるようにしたコンパイル時の静的な機能である。言語によってはテンプレート(template)と呼ばれる。ここでの「型」とはデータメンバの型やメソッドの引数値/返り値/計算値の型を指している。クラス内のそれらを総称化して型変数にし、コンストラクタ呼び出し時の仮型引数に実型引数を適用すると、型変数に実型引数を当てはめたインスタンスが生成される。総称化された型を持つクラスはジェネリッククラスと呼ばれる。特定の型に依存しないクラスを汎用的に定義できるので、型が違うだけの重複コードを削減できるという利点がある。パラメトリック多相とされる。言語によっては、ジェネリッククラス同士を共変性と反変性による継承関係で結ぶことができる。これはジェネリッククラスに適用する実型引数の継承関係を、そのジェネリッククラス同士の継承関係にシフトする仕組みである。
class 猫 extends 動物
とするとList<猫>
はList<動物>
のサブクラスになる。共変性は実型引数の継承関係をそのままジェネリッククラスの継承関係にシフトするが、反変性ではこれを逆にする。共変性ではList<猫>
はList<動物>
のサブクラスだが、反変性ではList<動物>
はList<猫>
のサブクラスになる。共変性と反変性はまとめてバリアンス(variance)と呼ばれる事がある。 - 型制約
- (type constraint)は、(A)ジェネリッククラスの型引数/型変数、(B)代入値の型が実行時に決められる動的束縛型の変数、(C)動的ローディング時に詳細が隠されたままの値が代入される不透明型の変数、などの宣言に用いられるものである。それぞれは制約用の基準クラスで記号修飾され、その基準クラス及びその派生型の値が代入、束縛、適用されるという宣言になる。(A)の型引数/型変数では基準クラス及びその派生クラスが適用される宣言になる。(B)の動的束縛型では基準クラス及びその派生型の値が代入される宣言になる。(C)の不透明型では基準クラス及びその詳細不明である派生型の値が代入される宣言になる。型制約は型境界(type bound)とも呼ばれる。これには上限と下限がある。型制約と上限型境界(upper type bound)は性質的に同義である。下限型境界(lower type bound)は、基準クラス及びその基底型の値が代入、束縛、適用されるという宣言になる。
- タイプメンバ
- (abstract type member)はジェネリッククラスのメンバ要素であり、ジェネリッククラス同士で型変数の内容をやり取りするための仲介要素である。Aクラスコンストラクタの型引数にBクラスを適用した際に、適切な代入定義が併記されたAクラス内のタイプメンバに、Bクラスがその内部で扱っている総称型もセットで適用できる。連想配列さながらにBクラスがキー的存在になってAクラスのタイプメンバ内容も決定されることから、この仕組みは関連型または連想型(associated type)と呼ばれる。
- 関数オブジェクト
- オブジェクト指向下の関数オブジェクト(function object)は、メソッドそのものをオブジェクトして扱うというプログラム概念である。関数型プログラミングのクロージャをモデルにしている。インスタンスを単に関数名らしく見せるための糖衣構文である( )演算子オーバーロードや、メソッドシグネチャを型種にした関数ポインタ型の変数であるデリゲートなどの実装形式がある。デリゲート変数にはインスタンスメソッドへの参照が代入されてクラス種類とそのインスタンス種類による処理の多相を表現できる。プロトタイプベースにおける関数はオブジェクトそのものと言える存在であり、ローカル変数がプロパティ存在になっているのでクロージャが自然表現できる他、写像の型として解釈されるローカル変数はメソッドの表現手段になる。そのメソッドの引数構成もプロパティ存在になっている場合はそれも変更できてクラスベースにおけるリフレクションを自然表現する。
- コルーチン
- オブジェクト指向下のイテレータ、ジェネレータ、デコレータは、コルーチン(coroutine)機構に基づいている。通常のサブルーチンがコールする側の復帰アドレスだけをスタックに積むのに対して、コルーチンはコールする側とコールされる側双方の復帰アドレスをスタックに積むというサブルーチン機構である。各要素への作用が記されたオペレータが無名関数やラムダ式などの形態でデータコンテナに渡されると、各要素をフェッチするデータコンテナと、フェッチされた要素を参照ないし加工するオペレータが交互にコールスタックを用いて連携動作を繰り返す。イテレータはオペレータをそのまま扱う機能である。ジェネレータはオペレータが反復処理を終えた後にその総和値や選別リストを生成する機能である。デコレータはメソッドをデータコンテナと見なしそのメソッド内での関数コールをそれぞれ要素にして、オペレータがフェッチされた関数名と引数欄を見ながら任意の処理を挿入する機能である。
- メッセージレシーバー
- (message receiver)はメッセージを受け取ることに特化されたメソッドである。メッセージレシーバーはインスタンスのデフォルトで呼び出される窓口レシーバーの形態と、指定メソッドが存在していない時に呼び出される補足レシーバーの形態がある。窓口レシーバーのメッセージはセレクタと引数のペアまたはそのどちらかだけという書式である。窓口レシーバーは極めて柔軟なプロセスを実現できるが、実装の煩雑さとオーバーヘッドが大きくなる。セレクタは識別子またはペア引数の注釈になる文字列である。セレクタはメソッドへの自動分岐が主な用途になるが、そのフィルター処理と取りこぼし処理の中でただのキーワードとしても自由に解釈できる。補足レシーバーのメッセージはメソッド名文字列と引数配列という書式になっており、いかなるメソッドシグネチャにも該当しなかった取りこぼしになる。このメソッド名文字列と引数配列を自由に解釈して柔軟な処理を行える。補足レシーバーの機能名はメソッドミッシングなどである。
- イミュータブル・オブジェクト
- (immutable object)は、データメンバが不変のクラスとそのインスタンスを指す。定数データメンバだけを持つクラスとも読み替えられる。文字列型やボックス型の定数オブジェクトも指す。イミュータブル(不変)はオブジェクトの性質というよりも、それを何のためにどう扱うかというプロセスまたはアルゴリズムの方が要点になる。不変オブジェクトは並行OOPと関数型OOPで最も重要視される。不変オブジェクトではセッターとミューテイタは禁止され、代わりに元への変更を反映して新たに生成したオブジェクトが返されることになる。この不変オブジェクトを取り扱う際のプログラミングスタイルは従来のOOPから大幅に変わる。ただし不変オブジェクトをコピーした専用の可変オブジェクトを取得したのならば、それへのセッターとミューテイタは許される。これはcopy-on-writeと呼ばれる仕組みである。
- デリゲーション
- 委譲(delegation)。呼び出されたあるクラスのメソッドが自分への引数を他のクラスの同名メソッドにそのまま渡して、その同名メソッドからの返り値をそのまま呼び出し元に渡すという仕組みを指す。委譲先のクラスはhas-a関係で保有されているものになる。委譲先メソッドは必ずしも同名ではなくマッピング名の場合もあり、引数も構成を変えて渡される場合もある。
- フォワーディング
- 転送(forwarding)。委譲先のクラスのメソッドが処理を行わずに、そのまた他のクラスの同名メソッドに引数をそのまま渡して、その返り値をそのまま呼び出し元に渡している場合、冒頭の委譲は転送になる。転送用メソッドではどのクラスに引数をパスするかという選択が行われるので、デリゲーションの多相を表現できる。
- サブタイピング
- (subtyping)はクラス(型)のあらゆる派生関係および派生構造の実装形式とその働き方を包括したプログラム概念である。サブタイプ多相(subtype polymorphism)とも呼ばれる。継承、オーバーライド、コンポジション、ジェネリクス、共変反変バリアンス、不透明型といったものは全てサブタイピングの一側面である。オブジェクト指向でよく使われるものは振る舞いサブタイピング(behavioral subtyping)であり、これに当てはまるものは継承とメソッドオーバーライドを組み合わせた仮想関数である。
- Is-a関係
- (Is-a)は上位概念と下位概念のコンセプトを扱っており、下位概念is-a上位概念となる。オブジェクト指向ではクラスの継承関係および実装継承関係を意味する用語になっている。これには汎化・特化・実現・実装の四種がある。
- 汎化(generalization)は、サブクラスからスーパークラスへの連結を指す。
- 特化(specialization)は、スーパークラスからサブクラスへの連結を指す。
- 実現(realization)は、クラスからインターフェースへの連結を指す。
- 実装(implementation)は、インターフェースからクラスへの連結を指す。
- Has-a関係
- (Has-a)は上位集合と部分集合のコンセプトを扱っており、上位集合has-a部分集合となる。オブジェクト指向ではクラスの構成関係を意味する用語になっている。これには合成・集約・収容・依存の四種がある。なお、依存(dependency)はhas-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)は弱いhas-a関係であり、集約と同じであるが、Aクラスがコレクション(配列、List、Set、Map)の仕組みでBインスタンスを持つ場合のみを指している。コレクション関係を強調する場合、AはBを収容しているとなる。
- 依存(dependency)は強いhas-a関係であり、Aクラスのいずれかのメソッドが、Bクラスを引数の型または返り値の型にしている場合、AはBに依存しているとなる。なお、AクラスがBクラスの型のデータメンバをhas-aしている場合のAからBへの依存は、合成/集約の方で省略されている。
- SOLID原則
- (SOLID Principles)は、いわゆる抽象化に焦点を当てたクラスの設計原則である。(S)単一責任原則・(O)解放閉鎖原則・(L)リスコフの置換原則・(I)インターフェース分離原則・(D)依存性逆転原則といった五つから成り立っている。1988年にバートランド・メイヤーが提唱した(O)と、1994年にバーバラ・リスコフが提示した(L)に、ソフトウェア技術者ロバート・マーティンが(S)(I)(D)を加えて2000年に発表されている。
- (S)単一責任原則は、クラスをただ一つの機能を表現するようにデザインすることを推奨している。
- (O)解放閉鎖原則は、クラスを抽象クラスと実装クラスに分けてデザインすることを推奨している。抽象クラスの定義内容は変更に閉じられており、実装クラスの処理内容は拡張に開かれていることが由来である。
- (L)リスコフの置換原則は、実装クラスはその抽象クラスに対して振る舞い的に等価計算が可能であることを推奨している。抽象側の公開保有メソッドを実装側も全て保有していれば等価となる。ここでの置換(substitution)とは抽象クラスの型の変数に実装クラスの型のインスタンスを代入できることを意味している。
- (I)インターフェース分離原則は、一つのクラスから実現される抽象クラスを一つに限定せず、互いに処理内容に影響し合うメソッド群ごとに分離して複数実現することを推奨している。
- (D)依存性逆転原則は、AクラスがBクラスの機能を使用したい場合は、まずBからその抽象クラスをAに向けて実現し、Aはその抽象クラスを通してBの機能を使用することを推奨している。AはBの機能を使用するという意味でその抽象クラスに依存し、Bは自身の機能を提供するという意味でその抽象クラスに依存することになる。ここでの逆転(inversion)とは実装から抽象への方向性を意味している。
- GOFデザインパターン
- (Gang of Four Design Patterns)はソフトウェア開発において直面しやすい共通的かつ代表的なデザイン問題をピックアップし、それぞれの解決に最適なクラスパターン図を提示したものである。1994年から四人の計算機科学者ないしソフトウェア技術者たち(Gang of Four)によって発表され、OOPのデザインパターンの代表格と見なされた。教科書の内容としても取り上げやすい形式化されたトピックであったためにオブジェクト指向の学習面では非常に重視された。5個の生成パターン、7個の構造パターン、11個の振る舞いパターンに分類されている。
- 生成に関するパターン
- 構造に関するパターン
- 振る舞いに関するパターン