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

削除された内容 追加された内容
m Interwiki link written as an external link
(同じ利用者による、間の5版が非表示)
11行目:
 
== 特徴 ==
現行のオブジェクト指向プログラミングは、1974年に計算機科学者[[バーバラ・リスコフ]]らが提唱した[[抽象データ型]]を基礎的な考え方にする方向性で定着している。[[抽象データ型]]のプログラム実装スタイルを具体的に規定したものが1 - 3であり、日本では一般に三大要素と呼ばれている。これに沿った言語仕様を備えたプログラミング言語がオブジェクト指向準拠と判別されている。4は[[アラン・ケイ]]が重視する元祖的なコンセプトであり、オブジェクト指向の源流思想として蛇足ながら紹介を加える。
 
#[[カプセル化]](''encapsulation'')
28行目:
 
=== メッセージパッシング ===
{{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 wanted to get rid of data. ... 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}}
 
== 歴史 ==
1954年に初の[[高水準言語]]・[[FORTRAN]]が登場すると、開発効率の劇的な向上と共にソフトウェア要求度も自然と高まりを見せてプログラム規模の急速な拡大が始まった。それに対応するために肥大化したメインルーチンを[[サブルーチン]]に分割する手法と、[[スパゲティプログラム|スパゲティ化]]した[[Goto文|goto命令]]を[[制御構造|制御構造文]]に置き換える手法が編み出され、これらは1960年に公開された言語「[[ALGOL|ALGOL60]]」で形式化された。当時のALGOLは[[アルゴリズム]]記述の一つの模範形と見なされたが、それと並行して北欧を中心にした計算機科学者たちはより大局的な観点によるプログラム開発技法の研究を進めていた。
42 ⟶ 41行目:
=== 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) ===
49 ⟶ 48行目:
 
=== プロトタイプベースの考案(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に導入されたメタオブジェクト設計は、後に[[プロトタイプベース]]またはインスタンスベースと呼ばれるパラダイムに発展する。同時にそれと、従来の[[クラス (コンピュータ)|クラス]]機構を中心にしたオブジェクト指向言語を区別するための[[クラスベース]]という言葉も生まれた。
 
=== コンポーネントとネットワーク(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]]策定は、オブジェクト指向プログラミングの標準化を促進させた。{{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}}
 
== 代表的なオブジェクト指向言語 ==
58 ⟶ 57行目:
[[ファイル:History of object-oriented programming languages.svg|境界|中央|フレームなし]]
;[[Simula|Simula 67]] 1967年
:1962年に公開された[[Simula]]の後継バージョンであり、[[クラス (コンピュータ)|クラス]]のプログラム概念を導入した最初の言語である。物理モデルを解析するシミュレーション制作用に開発されたもので、クラスをメモリに展開したオブジェクトはその観測対象要素になった。Simulaのクラスは、一つのローカル変数構造と複数のプロシージャをまとめたミニモジュールと言えるものであったが、継承と仮想関数という先進的な設計を備えていた事でオブジェクト指向言語の草分けと見なされるようになった。[[クラスベース]]の源流である。
;[[Smalltalk]] 1972年
:[[メッセージパッシング]]のプログラム概念を導入した最初の言語。数値、真偽値、文字列から変数、コードブロック、メタデータまでのあらゆる要素をオブジェクトとするアイディアを編み出した最初の言語でもある。オブジェクト指向という言葉はSmalltalkの言語設計を説明する中で生み出された。オブジェクトにメッセージを送るという書式であらゆるプロセスを表現することが目標にされている。[[メッセージ転送|メッセージレシーバー]]と[[委譲]]の仕組みは、形式化されていない動的ディスパッチと[[ダイナミックバインディング|動的バインディング]]相当のものであり[[プロトタイプベース]]の源流にもなった。GUI運用環境に統合された専用のランタイム環境上で動作させる設計も模範にされ、これは後に[[仮想マシン]]や[[仮想実行システム]]と呼ばれるものになる。
86 ⟶ 85行目:
:[[Java]]を強く意識してマイクロソフト社が開発したクラスベースのオブジェクト指向言語。C++の柔軟性と融通的を残しながら、[[テンプレートメタプログラミング]]的なコーディングサポートも加えてマルチパラダイムに発展させている。アドホック多相では拡張メソッド、インデクサ、演算子オーバーロードなどを備えている。パラメトリック多相ではジェネリクスの型変数の[[共変性と反変性 (計算機科学)|共変性と反変性]]、型引数の型制約などを備えている。サブタイプ多相はクラスは単一継承でインターフェースは多重実装と基本通りである。[[関数型言語|関数型構文]]では特にデリゲートの有用性が高い。基本は[[静的型付け]]であるが、動的束縛型と[[ダックタイピング]]による[[動的型付け]]の存在感が高められているので漸進的型付けの言語と見なされている。[[.NET Framework]]([[共通言語基盤]]=仮想実行システム)上で実行される。
;[[Scala]] 2003年
:[[クラスベース]]のオブジェクト指向と[[関数型プログラミング]]を融合させた言語。[[クラス (コンピュータ)|クラス]]機構と関数型の[[型システム]]に同等の比重が置かれており静的型付け重視である。[[ミックスイン]]相当の[[トレイト]]と[[ジェネリクス]]を連携させた多態性が重視されている。型変数の[[共変性と反変性 (計算機科学)|バリアンス]]、[[共変性と反変性 (計算機科学)|共変と反変]]双方の型境界、抽象タイプメンバ、ジェネリックトレイト、抽象クラスの組み合わせでオブジェクトを様々に[[派生型|派生型付け]]できる。シングルトンオブジェクトの役割が形式化されて従来のクラス静的メンバの新解釈にも用いられている。専用の定義書式により[[イミュータブル]]なオブジェクトが重視されている。上述の派生型付けスタイルとオブジェクト引数の[[逆写像|抽出]]構文とオブジェクトの[[パターンマッチング|パターンマッチング式]]とオブジェクト引数の[[逆写像|抽出]]構文の併用連鎖計算は[[モナド (プログラミング)|モナド]]を彷彿とさせるものであり、[[抽象データ型]]を値として扱う独特の関数型スタイルを表現できる。[[Java仮想マシン]]上で動作するJavaテクノロジ互換言語である。
;[[Kotlin]] 2011年
:静的型付けの[[クラスベース]]のオブジェクト指向であるが、[[手続き型プログラミング]]に回帰しており、クラス枠外の関数とグローバル変数の存在感が高められている。クラスはpublicアクセスとfinal継承がデフォルトにされて、カプセル化と継承が公然と軽視されている。これによりインスタンスは手続き型の関数の対象値としての役割が強められ、その操作をサポートする関数型構文も導入されている。仮想関数と抽象クラスによる多態性は標準通りである。[[Java仮想マシン]]上で動作するJavaテクノロジ互換言語である。
100 ⟶ 99行目:
:プロトタイプ(''prototype'')の仕組みを中心にしたオブジェクト指向を[[プロトタイプベース]]と言う。プロトタイプベースで言われるオブジェクトとは、中間参照ポインタの動的配列を指す。この動的配列は一般にフレームと呼ばれる。中間参照ポインタは一般にスロットと呼ばれる。スロットにはデータメンバとメソッドの参照が代入されるので、オブジェクトはクラスと同様にデータメンバとメソッドをまとめたものになる。プロトタイプベースの実装形式は言語ごとに様々であるが基本は概ね以下のようになる。オブジェクトはプロトタイプオブジェクトとクローンオブジェクトに分かれる。前者はクラス、後者はインスタンスに当たるものである。前者はシステム提供プロトタイプとユーザー定義プロトタイプに分かれる。プログラマはシステム提供プロトタイプを派生させてユーザー定義プロトタイプを作成する。プロトタイプは規定または事前の設計に基づいたデータメンバとメソッドを保持しており、クローンオブジェクトのひな型になる。クローンはそのプロトタイプへの参照を保持しており、プロトタイプはその親プロトタイプへの参照を保持している。これは継承相当の機能になる。プロトタイプを複製してクローンオブジェクトが生成される。クローンオブジェクトはそのプロトタイプと同じデータメンバとメソッドを保持する事になるが、プロトタイプ専用に指定されたメンバは除かれる。クローンオブジェクトのメソッドは自由に付け替えできるので、これは多態性相当の機能になる。
;[[メッセージ (コンピュータ)|メッセージ]]
:オブジェクト指向で言われるメッセージ(''message'')は、複数の方面の考え方が混同されている曖昧な用語になっている。元々はSmalltalkから始まったメッセージ構文ベースのオブジェクト指向の中心機構である。以前はクラスベースの方でもメソッドの呼び出しをメッセージを送るという風に考えることが推奨されていた。メッセージはオブジェクトのコミュニケーション手段と標榜されているが、その忠実な実装内容はそれほど知られていないのが実情である。最も混同されているものに[[アクターモデル]]があるが、そこで言われる非同期性とオブジェクト指向で言われる評価の遅延性は現行の実装スタイルではそれほど共通していない。[[ソフトウェアコンポーネント準拠ソフトウェア工学]]と[[Object Request Broker|オブジェクトリクエストブローカー]]で言われる[[ソフトウェアコンポーネント]]同士の相互通信もメッセージパッシングと呼ばれることが多いが、その仕様と機能は動的ディスパッチに該当するものである。メッセージのオブジェクト指向的運用はメッセージングと名付けられている。具体的な機能例としてはSmalltalk、Objective-C、Selfの[[メッセージ転送|メッセージレシーバー]]と、Rubyのメソッドミッシングなどがあるが、いずれもメッセージングの本質ではないとも言われている。
;[[インスタンス]]
:(''instance'')はクラスベースではクラスを実体化(量化)したものであり、実装レベルで言うとデータメンバと仮想関数テーブルをメモリ上に展開したものになる。プロトタイプベースではプロトタイプオブジェクトのクローンで生成されたオブジェクトを指す。実装レベルで言うとメモリ上に展開された中間参照ポインタの動的配列になる。
120 ⟶ 119行目:
:(''copy constructor'')は、メソッドの引数に対する値インスタンスの値渡しの時に呼び出されるコンストラクタである。値渡しはインスタンス内容全体のメモリコピーであり、基本データ型では特に問題は生じないが、そうでないクラスのインスタンスでは例えばあるリソースへの参照を保持している場合に好ましくない保持重複が発生する事になる。呼び出されたコピーコンストラクタは値インスタンスを受け取り、単純コピーが許されない部分に任意の処理を施して生成した値インスタンスのコピーを引数へと渡す。
;[[オーバーロード]]
:(''overloading'')は一つのメソッド名に複数のそれぞれ異なるパラメータリスト(引数欄)を付けたものを任意の数だけ列挙してメソッド名を多重定義すること仕組みを指す。[[演算子]]もオーバーロード対象であり、[[単項演算子]]なら一つの引数の型、[[二項演算子]]なら二つの引数の型を多重定義することで演算対象の値の型ごとに計算内容をカスタマイズできる。任意数の引数の型を多重定義できる( )演算子は、[[クロージャ]]または[[関数オブジェクト]]の表現に用いられる。アドホック多相とされる。
;メソッド拡張
:(''method extension'')は、クラス定義とは別の場所でそのクラスに対する追加メソッドを定義できる機能である。これは状況に合わせてデータ抽象の表現に幅を持たせることを目的にしている。これには数々の書式があるが代表的なのは、静的メソッドまたは静的関数の第1引数をthis修飾して、その第1引数のクラス(型)に対してその静的メソッドをインスタンスメソッドとして追加するというものである。静的メソッドはそのクラススコープ内の限定拡張にできる。静的関数はネスト関数にしてそのローカルスコープ内の限定拡張にできる。双方はグローバル用途にすることもできる。アドホック多相とされる。
129 ⟶ 128行目:
;[[仮想継承]]
:(''virtual inheritance'')は、多重継承での[[菱形継承問題]]を回避するための仕組みである。菱形継承問題とは共にAクラスを親とするBクラスとCクラスの双方を継承した場合に、その継承構造上でAクラスが二つ重なって存在することになる不具合である。仮想継承では専用のテーブルが用意されて、そこでクラス名が参照アドレスにマッピングされる。BクラスからのAクラスと、CクラスからのAクラスは共に同じ参照アドレスをマッピングするのでAクラスはひとつにまとめられる事になる。同時に一度辿ったクラスは省略される事にもなる。
;メソッド解決順序
;C3線形化
:(''C3method linearizationresolution order'')は、多重継承で用いられ時の親クラスの巡回順序を定義す幅優先である。参照されたメソッド解決順序(''Method Resolution Order'')であが自クラスにない場合はその親クラスを巡回してサーチされる。メソッドはクラスメンバと読み替えてもよい。自クラス内に無いメンバをこれは[[深さ優先すための親索|深さ優先検索]](''deep-first'')と[[幅優先探索|幅優先検索]](''breadth-first'')に分かれるが、オブジェラス順序を決定する仕組みであ構造概念から深さ優先の方が自然とされている。従って一般的な多重継承では深さ優先検索によるメソッド解決順序が用いられて親クラスの重複は仮想継承で解決されている。しかし詳細は割愛するが、仮想継承部分の巡回順序に不自然さを指摘する意見もあったので、こを解決するため深さ優先と幅優先をミックスC3線形化では、深(''C3 linearization'')というメソッド解決順序が考案レベルを先行基準にし。C3線形化では親クラスの整列と重複部分に対た親クラスのマージが行われ、そ結果の親クラス線形化リストは幅優先検索を適用することで、仮想継承を用いることく菱形継承問題も自然に解決されている。
;[[抽象クラス]]
:(''abstract class'')は、クラスメンバの一部のメソッドだけが抽象化されているクラスを意味する。抽象化されたメソッドとは、メソッドシグネチャ(返り値+メソッド名+引数欄)だけが定義されてコード内容が省略されているメソッドを意味する。抽象クラスはインスタンス化できないので継承専用になる。抽象メソッドは、サブクラスの方でメソッドのコード内容が実装されてオーバーライドされる。
;[[インタフェース (抽象型)|インターフェース]]
:(''interface'')はプログラム概念と機能名の双方を指す用語である。言語によってはプロトコルと言われる。抽象メソッドと実メソッドをメンバにできる純粋抽象〜半抽象クラスを意味する。クラスの振る舞い側面を抜き出した抽象体である。クラスによるインターフェースの継承は実装と呼ばれる。多重実装可が普通である。ミックスインとの違いは、抽象階層に焦点が当てられている事であり、直下の実装オブジェクトを共通の振る舞い側面でまとめることがその役割である。インターフェースは自身の[[下位概念]]である実装継承オブジェクトをグループ化できる。{{仮リンク|記名的型付け|en|Nominal type system|label=}}に準拠しているのでインターフェースの実装の明記が振る舞い側面の識別基準になる。インターフェースは抽象メソッド主体なので多重継承時のメンバ名の重複はあまり問題にならない。共通の実装メソッドに集約されるからである。インターフェースは非インスタンス対象である。
;[[ミックスイン]]
:(''mixin'')はインターフェースに似たプログラム概念を指す用語である。機能名は言語によって[[トレイト]]、プロトコル、構造型(''structural type'')と言われる。抽象メソッドと実メソッドとデータメンバをメンバにできる継承専用クラスを意味する。クラスを特徴付けるための構成パーツである。クラスによるトレイトの継承は実装と呼ばれる。多重実装可が普通である。インターフェースとの違いは、トレイトの実装階層に焦点が当てられている事であり、オブジェクトを所有メンバで特定してまとめることがその役割である。トレイトは自身の[[上位集合]]である実装継承オブジェクトをグループ化できる。{{仮リンク|構造的型付け|en|Structural type system|label=}}に準拠しているので所属メンバ構成自体がトレイト等価性の識別基準になる。これはトレイト実装を明記していなくても、そのトレイトが内包する全メンバを所持していれば同じトレイトと見なされることを意味する。トレイトは合成や交差が可能である。トレイトは多重継承時のメンバ名重複の際にその参照の優先順位に注意する必要がある。トレイトは非インスタンス対象である。
;型イントロスペクション
:''(type introspection'')は一般に実行時型チェックと呼ばれるものである。プログラマが認知できない形でコンパイラまたはインタプリタが別途実装しているインスタンスの型情報を、実行時にその都度参照してインスタンスの型を判別する仕組みである。静的型付け下では専用の実行時型チェック構文(instanceofやdynamic_cast)によって型判別し、ダウンキャストなどに繋げられる。動的型付け下では変数への再代入時や関数への引数適用時にランタイムシステムが自動的に型判別し、多重ディスパッチなどに繋げられる。型イントロスペクションでは型情報のタグ識別子が判定基準になっているので{{仮リンク|記名的型付け|en|Nominal type system|label=}}の考え方に準じている。
;[[ダックタイピング]]
:''(duck typing'')は、特定のデータメンバ名またはメソッド名(メソッドシグネチャ)またはプロパティ名(データメンバ名)の識別子を持っているかどうかでインスタンスをその都度分類すること仕組みであるまたこれその場限分けるこの型判別言えるものである選り分けら判別されたインスタンスはその指名データメンバないし指名自身が持つとされたメソッドでのアクセス対象またはプロパティを呼び出される事になる。動的型付けの機能であり、ダックタスタンス、変数、オブジェクトを実行時に逐次グでは型情報の構成内容が別すると定基準になってう点るの{{仮リンク|構造的推論と区別され付け|en|Structural type system|label=}}の考え方に準じている。
;[[型推論]]
:オブジェクト指向下の型推論''(type inference'')は、型宣言ないし型注釈を省略して定義された変数の「型」が自動的に導き出される機能を指す。型はクラスと同義である。静的型付けの機能であり、コンパイラまたはインタプリタがソースコードをあらかじめ解析しながら値の代入を始めとしたその変数の扱われ方によって型を導き出す。ここで導き出される「型」とは他の変数への代入可能性や、関数の引数への適用可能性といったあくまで等価性の基準で決められるので、プログラマが人為的な意味付けによる型定義を重視している場合は予期せぬ結果が発生することにもなる。
;[[メタクラス]]
:(''metaclass'')とはクラス自体の定義情報であり、そのクラスが持つとされるデータメンバ、メソッド、スーパークラス、内部クラスなどの定義が記録されたいわゆる[[メタデータ]]である。実装レベルでは、システム側が用意している特別なシングルトンオブジェクトと考えた方が分かりやすい。メタクラスの各種定義情報を参照または変更する機能はリフレクションと呼ばれる。メタクラスの変更はその対象クラスに直ちに反映される。クラスベースで用いられるものである。
148 ⟶ 149行目:
:(''metadata annotation'')はクラスに任意の情報を埋め込める機能である。情報とは文字列と数値からなるキーワード、シンボル、テキストである。プログラマが自由な形式で書き込んで随時読み取るものであるが、システムから認識される形式のものもある。実装レベルではメタクラスに書き込まれてリフレクション機能またはその[[糖衣構文]]で読み取ることになる。[[マーカーインタフェース|マーカーインターフェース]]の拡張とも見なされている。メタアノテーションはクラス単位だけでなく、言語によってはインスタンス単位やメソッド単位でも埋め込むことができる。アドホック多相とされる。
;動的ディスパッチ
:(''dynamic dispatch'')は、コンパイル時のメソッド名から呼び出されるメソッド内容が実行時に決定される仕組み全般を指す用語である。メソッドに引数を渡しての呼び出しを、オブジェクトにメッセージを発送(ディスパッチ)することになぞらえた事が由来である。発送先は実行時に選択決定されるメソッド内容を指す。メッセージは「[[This (プログラミング)|this参照]]×第1引数×第2引数..」といった[[直積集合]]で考えられているのでシングル、[[ダブルディスパッチ|ダブル]][[多重ディスパッチ|マルチプル]]といった呼称になっている。発送先はthisおよび各引数の派生関係の組み合わせで選択される。thisの派生関係のみ影響しているのは専ら仮想関数と呼ばれるシングルディスパッチであになる。それがthisでなく引数ならばただのシングルになる。thisまたは各引数の内の2個以上のオブジェクトの派生関係が影響しているのはダブルないし[[多重ディスパッチ|マルチプルディスパッチ]]になる。その中で特にthisと先頭引数の2個が影響して先頭引数インスタンスの仮想関数がthisを引数にしているVisitor形態のものは[[ダブルディスパッチ]]と呼ばれている。
;[[動的束縛|動的バインディング]]
:(''dynamic binding'')は、識別子が参照するまたは呼び出すオブジェクト、インスタンス、メソッド、データメンバなどのプログラム要素が、コンパイル時ではなく実行時に決められる仕組み全般を指す用語である。識別子はいわゆる変数名や関数名などを指す。
 
;遅延バインディング
:(''late binding'')は、識別子が参照するオブジェクトをコンパイル時に決める事前バインディング(''early binding'')の対義語であり、この場合は識別子が参照するオブジェクトを実行時に決める動的バインディングと同じ意味で用いられる。また他方では動的バインディングの中で、特に実行コードの動的ローディング機能を通して実装される方を遅延バインディングとする考え方もある。実行コードとは[[ダイナミックリンクライブラリ|DLL]]やクラスライブラリやモジュールなどを指しており、それらが内包するクラスやメソッドを専用の不透明型または動的束縛型に代入する。その呼び出しのための内部識別子はコンパイル時には存在していないことが多いので、実行時の文字列(char配列やString)を内部識別子に解釈するためのリフレクション機能が多用されることになる。
 
;[[パッケージ (Java)|パッケージ]]
173 ⟶ 174行目:
:(''abstract type member'')はジェネリッククラスのメンバ要素であり、ジェネリッククラス同士で型変数の内容をやり取りするための仲介要素である。Aクラスコンストラクタの型引数にBクラスを適用した際に、適切な代入定義が併記されたAクラス内のタイプメンバに、Bクラスがその内部で扱っている総称型もセットで適用できる。連想配列さながらにBクラスがキー的存在になってAクラスのタイプメンバ内容も決定されることから、この仕組みは関連型(''associated type'')と呼ばれる。
;[[関数オブジェクト]]
:オブジェクト指向下の関数オブジェクト(''function object'')は、メソッドそのものをオブジェクトして扱うというプログラム概念である。関数型プログラミングの[[クロージャ]]をモデルにしている。単にインスタンスを単に関数名らしく見せるための糖衣構文である( )[[演算子オーバーロード]]や、メソッドシグネチャを型種にした[[関数ポインタ]]型の変数である[[デリゲート (プログラミング)|デリゲート]]などの実装形式がある。デリゲート変数にはインスタンスメソッドへの参照が代入されてクラス種類とそのインスタンス種類による処理の多相を表現できる。プロトタイプベースにおける関数はオブジェクトそのものと言える存在であり、ローカル変数がプロパティ存在になっているのでクロージャが自然表現できる他、写像の型として解釈されるローカル変数はメソッドの表現手段になる。そのメソッドの引数構成もプロパティ存在になっている場合はそれも変更できてクラスベースにおけるリフレクションを自然表現する。
;[[コルーチン]]
:オブジェクト指向下の[[イテレータ]]、[[ジェネレータ (プログラミング)|ジェネレータ]]、デコレータは、コルーチン(''coroutine'')機構に基づいている。通常のサブルーチンがコールする側の復帰アドレスだけをスタックに積むのに対して、コルーチンはコールする側とコールされる側双方の復帰アドレスをスタックに積むというサブルーチン機構である。各要素への作用が記されたオペレータが[[無名関数]]やラムダ式などの形態で[[コンテナ (データ型)|データコンテナ]]に渡されると、各要素をフェッチするデータコンテナと、フェッチされた要素を参照ないし加工するオペレータが交互に[[コールスタック]]を用いて連携動作を繰り返す。イテレータはオペレータをそのまま扱う機能である。ジェネレータはオペレータが反復処理を終えた後にその総和値や選別リストを生成する機能である。デコレータはメソッドをデータコンテナと見なしそのメソッド内での関数コールをそれぞれ要素にして、オペレータがフェッチされた関数名と引数欄を見ながら任意の処理を挿入する機能である。
187 ⟶ 188行目:
:転送(''forwarding'')。委譲先のクラスのメソッドが処理を行わずに、そのまた他のクラスの同名メソッドに引数をそのまま渡して、その返り値をそのまま呼び出し元に渡している場合、冒頭の委譲は転送になる。転送用メソッドではどのクラスに引数をパスするかという選択が行われるので、デリゲーションの多相を表現できる。
 
;[[Is-a|Is-a関係]]
;汎化
:(''Is-a'')は[[上位概念、下位概念、同位概念および同一概念|上位概念と下位概念]]のコンセプトを扱っており、下位概念is-a上位概念となる。オブジェクト指向ではクラスの継承関係および実装継承関係を意味する用語になっている。これには汎化・特化・実現・実装の四種がある。
:* 汎化(''generalization'')は継承による[[is-a]]関係であり、サブクラスからスーパークラスへの連結を指す。
;特化
:* 特化(''specialization'')は継承による[[is-a]]関係であり、スーパークラスからサブクラスへの連結を指す。
:* 実現(''realization'')は、クラスからインターフェースへの連結を指す。
;実現
:* 実装(''realizationimplementation'')はクラスの振る舞いの抽象化による[[is-a]]関係でありクラスからインターフェースからクラスへの連結を指す。振る舞いとは特定の目的に沿ったメソッド群である
;[[Has-a|Has-a関係]]
;実装
:(''Has-a'')は[[部分集合|上位集合と部分集合]]のコンセプトを扱っており、上位集合has-a部分集合となる。オブジェクト指向ではクラスの構成関係を意味する用語になっている。これには合成・集約・収容・依存の四種がある。なお、依存(''dependency'')はhas-a関係における依存とそれ以外のクラス間関係における依存の意味が異なる二つが存在する。
:(''implementation'')はクラスの振る舞いの抽象化による[[is-a]]関係であり、インターフェースからクラスへの連結を指す。振る舞いとは特定の目的に沿ったメソッド群である。
:* 合成(''composition'')は強いhas-a関係であり、AクラスがBクラスをデータメンバにし、Aクラスのコンストラクタと同時にBインスタンスが生成され、Aクラスのデストラクタと同時にBインスタンスが破棄される場合、AはBの合成となる。Bが自身のサブクラスで交換される場合は分離とともに破棄される。
;合成
:* 集約(''compositionaggregation'')は[[has-a]]関係であり、AクラスがBクラスをデータメンバにし、Aクラスのコンストラクタと同時には関係なくBインスタンスが生成され、Aクラスのデストラクタと同時にBインスタンスが破棄されず、また分離時も破棄されない場合、AはBの合成集約となる。Bが自身のサブAクラスがコレクション(配列、List、Set、Map)の仕組み交換されるBインスタンスを持つ場合も、A分離とBの集約もに破棄される。
:* 収容(''containment'')は弱いhas-a関係であり、集約と同じであるが、Aクラスがコレクション(配列、List、Set、Map)の仕組みでBインスタンスを持つ場合のみを指している。コレクション関係を強調する場合、AはBを収容しているとなる。
;集約
:* 依存(''aggregationdependency'')は[[has-a]]関係。AクラスがBクラスをデータメンバにしであり、Aクラスのコンストラクタとは関係なくBインスタンスいずれかのメソッド生成されABクラスを引数デストラクタでBインスタンスが破棄されず、また分離時も破棄されなは返り値の型にして場合、AはBの集約に依存しているとなる。なお、AクラスがコレBション(配列、List、Set、Map)ラスの型仕組みでBインスデー持つ[[has-a]]している場合も、AからB依存は、合成/集約となる。コレクション性を強調する場合は収容(''containment'')とすることもあの方で省略されている。
;関連
:(''association'')。AクラスがBクラスのメソッドを呼び出す場合、AはBに関連しているとなる。AはBへの誘導可能性を持つとされる(A→B)。has-a関係で保有しているインスタンスのメソッドを呼び出すという意味で関連線は合成線または集約線と重ねて引かれることが多い。
;依存
:(''dependency'')。AクラスのメソッドがBクラスのインスタンスを引数または返り値にしている場合、AはBに依存しているとなる。返り値の例として、Aのメソッドがその返り値としてBインスタンスを生成する場合も、AはBに依存しているとなる。この「依存」は[[型理論]]上の意味に準拠した用語なのでやや分かり難くなっている。AクラスがBクラスの機能利用を必要とするなどの一般に想像しやすい意味での依存は「関連」になる。
 
;[[SOLID|SOLID原則]]
:(''SOLID Principles'')は、いわゆる抽象・特化・実現・実装・関連・依存の関係に焦点を当てたクラスの設計原則である。(S)単一責任原則・(O)解放閉鎖原則・(L)リスコフの置換原則・(I)インターフェース離原則・(D)依存向き原則といった五つから成り立っている。1988年に[[バートランド・メイヤー]]が提唱した(O)と、1994年に[[バーバラ・リスコフ]]が提示した(L)に、ソフトウェア技術者ロバート・マーティンが(S)(I)(D)を加えて2000年に発表されている。これはSOLIDの文字通りの順に解釈できるようになっている。
:* (S){{仮リンク|単一責任原則|en|Single-responsibility principle}}は、クラス(属性・操作)をただ一つの機能を表現するようにデザインすることを推奨している。
:* (O)[[開放/閉鎖原則|解放閉鎖原則]]は、クラスを抽象クラス(汎化・実現)と実装クラス(特化・実装)に分けてデザインすることを推奨している。抽象クラスの定義内容は変更に閉じられており、実装クラスの処理内容は拡張に開かれていることが由来である。
:* (L)[[リスコフの置換原則]]は、汎化と特化に対する枠組みであり、実装クラスはその抽象クラスに対して振る舞い的に等価計算が可能であるようにすることを推奨している。抽象側の公開保有メソッドを実装側も全て保有していれば等価となる。ここでの置換(''substitution'')とは抽象クラスの型の変数に実装クラスの型のインスタンスを代入できることを意味している。
:* (I){{仮リンク|インターフェース離原則|en|Interface segregation principle|label=}}は、実現と実装に対する枠組みであり、一つのクラスから実現される抽象クラスを一つに限定せず、互いに処理内容に影響し合うメソッド群ごとに離して複数実現することを推奨している。
:* (D)[[依存性逆転の原則|依存向き原則]]は、関連と依存に対する枠組みであり、AクラスからBクラスに向けて関連線の機能引き使用したい場合は、まずBからその抽象クラスをAに向けて実現し、Aはその抽象クラスに対を通してAからB関連線機能引く使用することを推奨している。AはBからの機能を使用するという意味でその抽象クラスへの依存線がAからBは自身関連線機能を提供するは逆向きいう意味でその抽象クラス依存することが由来であになる。ここでの依存線逆転(''inversion'')と実装から抽象クラス生成方向性を意味し、関連線はメソッドの呼び出しを意味すている。
 
; [[デザインパターン (ソフトウェア)|GOFデザインパターン]]
216 ⟶ 213行目:
: 生成に関するパターン<gallery heights="40">
ファイル: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]]
ファイル:Factory Method UML class diagram.svg|[[Factory Method パターン|Factory Method]]
ファイル:Prototype UML.svg|[[Prototype パターン|Prototype]]
ファイル:Singleton UML class diagram.svg|[[Singleton パターン|Singleton]]
</gallery>
: 構造に関するパターン<gallery heights="40">