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

削除された内容 追加された内容
m →‎用語と解説: い抜き言葉「やってる」「してる」の使用を回避(3回目)
(同じ利用者による、間の2版が非表示)
22行目:
 
=== 継承 ===
既存オブジェクトのデータ構成とメソッド構成を引き継いで、新しい派生オブジェクトを定義する仕組みが継承と呼ばれる。引き継ぐ際には新たなデータとメソッドを自由に追加できるので、派生オブジェクトの構成は既存要素+追加要素になる。既存の基底オブジェクトは親オブジェクト、その派生オブジェクトは子オブジェクトとも呼ばれる。クラスベースでは、親をスーパークラス、子をサブクラスと呼ぶ。一つのスーパークラスを継承するのは単一継承と呼ばれる。複数個のスーパークラスを継承してそれぞれの要素を引き継ぐのは多重継承と呼ばれる。[[統一モデリング言語|UML]]では汎化と特化の関係で表現されている。メソッドの抽象化に焦点を当てた継承の方は{{仮リンク|実装継承|en|3=https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)#:~:text=Implementation%20inheritance%20is%20the%20mechanism,class%20implementation%20with%20its%20own.}}などと呼ばれる。UMLでは実現と実装の関係で表現されている。実装継承は特定のオブジェクトたちに共通した振る舞い側面を抜き出して抽象化する仕組みを指し、その抽象オブジェクトは[[インタフェース (抽象型)|インターフェース]]、[[トレイト]]、{{仮リンク|プロトコル(OOP)|en|Protocol (object-oriented programming)|label=プロコトル}}などと呼ばれる。
 
=== 多態性 ===
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 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}}
 
== 歴史 ==
38行目:
=== 構造化プログラミングの提唱(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.''
<br>([[Sketchpad]]、[[Simula]]、[[アーパネット]]、[[バロース B5000|バロースB5000]]、それと専攻していた生物学と数学に影響されて僕はプログラミングアーキテクチャを思索していた)|Alan Kay}}1974年に[[MIT]]の計算機科学者[[バーバラ・リスコフ]]とステファン・ジルは「[[抽象データ型]]」というプログラム概念を提唱した。彼女らの理論は、ダイクストラが提示したモジュールの共同詳細化を、その振る舞いによって[[セマンティクス|意味内容]]が定義される抽象データという考え方でより明解に形式化し、データ階層ないしモジュール階層の連結関係を、[[上位概念、下位概念、同位概念および同一概念|上位概念と下位概念]]の[[リスコフの置換原則|置き換え原則]]で明確に標準化した。一方、1970年に構造化言語[[Pascal]]を開発していた計算機科学者[[ニクラウス・ヴィルト]]は、ダイクストラによる共著出版後の1975年にモジュール化言語[[Modula-2|Modula]]を提示してモジューラプログラミングというパラダイムを生み出している。このようにいささか奇妙ではあるが、Simulaのクラスとオブジェクトというプログラム概念は、巷で言われる構造化からモジュール化へといった進化の流れとは関係なく、しかもその前段階においてさながら彗星のように生まれたパラダイムであった。
 
=== Smalltalkとオブジェクト指向の誕生(1972 - 81) ===
46行目:
=== C++の開発(1979 - 88) ===
[[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をモデルにしてそれを平易化した言語であった。そのメッセージレシーバーはメソッドリストにないセレクタを受け取った場合にのみ動的ディスパッチ機構に移るというスタイルで形式化された。程なくしてこのメッセージレシーバー実装の必要性には疑問符が付けられるようになったが、[[遠隔手続き呼出し]]のスタイルにはマッチしていたのでメッセージにある種の理想を抱く風潮はいつまでも残った。
 
=== プロトタイプベースの考案(1985 - 90) ===
179行目:
:(''message receiver'')はメッセージを受け取ることに特化されたメソッドである。メッセージレシーバーはインスタンスのデフォルトで呼び出される窓口レシーバーの形態と、指定メソッドが存在していない時に呼び出される補足レシーバーの形態がある。窓口レシーバーのメッセージはセレクタと引数のペアまたはそのどちらかだけという書式である。窓口レシーバーは極めて柔軟なプロセスを実現できるが、実装の煩雑さとオーバーヘッドが大きくなる。セレクタは識別子またはペア引数の注釈になる文字列である。セレクタはメソッドへの自動分岐が主な用途になるが、そのフィルター処理と取りこぼし処理の中でただのキーワードとしても自由に解釈できる。補足レシーバーのメッセージはメソッド名文字列と引数配列という書式になっており、いかなるメソッドシグネチャにも該当しなかった取りこぼしになる。このメソッド名文字列と引数配列を自由に解釈して柔軟な処理を行える。補足レシーバーの機能名はメソッドミッシングなどである。
;[[派生型|サブタイピング]]
:(''subtyping'')はクラス(型)のあらゆる派生関係および派生構造の実装形式とその働き方を包括したプログラム概念である。サブタイプ多相(''subtype polymorphism'')とも呼ばれる。継承、オーバーライド、コンポジション、ジェネリクス、共変バリアンス、引数バリアンスによるディスパッチ、不透明型といったものは全てサブタイピングの一側面である。オブジェクト指向でよく使われるものは振る舞いサブタイピング(''behavioral subtyping'')であり、これに当てはまるものは継承とメソッドオーバーライドを組み合わせた仮想関数である。
 
;[[委譲|デリゲーション]]
202行目:
:(''association'')。AクラスがBクラスのメソッドを呼び出す場合、AはBに関連しているとなる。AはBへの誘導可能性を持つとされる(A→B)。has-a関係で保有しているインスタンスのメソッドを呼び出すという意味で関連線は合成線または集約線と重ねて引かれることが多い。
;依存
:(''dependency'')。AクラスのメソッドがBクラスのインスタンスを引数または返り値にしている場合、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クラスからの関連線と逆向きになることがその名の由来である。
 
;[[SOLID]]
; GOFデザインパターン
:(''SOLID Principles'')は、汎化・特化・実現・実装・関連・依存の連結線関係に焦点を当てたクラスの設計原則である。(S)単一責任原則・(O)解放閉鎖原則・(L)リスコフの置換原則・(I)インターフェース離原則・(D)依存の逆向き原則といった五つから成り立っている。19741988年に[[バーンドリスコフメイヤー]]が提唱した(LO)と、19881994年に[[バーンドメイヤーリスコフ]]が提した(OL)に、ソフトウェア技術者ロバート・マーティンが(S)(I)(D)を加えて2000年に発表されている。これはSOLIDの文字通りの順に解釈できるようになっている。
:(S){{仮リンク|単一責任原則|en|Single-responsibility principle}}は、クラス(属性・操作)をただ一つの機能を表現するようにデザインすることを推奨している。
:(O)[[開放/閉鎖原則|解放閉鎖原則]]は、クラスを抽象クラス(汎化・実現)と実装クラス(特化・実装)に分けてデザインすることを推奨している。抽象クラスの定義内容は変更に閉じられており、実装クラスの処理内容は拡張に開かれていることが由来である。
:(L)[[リスコフの置換原則]]は、汎化と特化に対する枠組みであり、実装クラスはその抽象クラスに対して振る舞い的に等価計算が可能であるようにすることを推奨している。抽象側の公開保有メソッドを実装側も全て保有していれば等価となる。
:(I){{仮リンク|インターフェース隔離原則|en|Interface segregation principle}}は、実現と実装に対する枠組みであり、一つのクラスから実現される抽象クラスを一つに限定せず、互いに処理内容に影響し合うメソッド群ごとに隔離して複数実現することを推奨している。
:(D)[[依存性逆転の原則|依存の逆向き原則]]は、関連と依存に対する枠組みであり、AクラスからBクラスに向けて関連線を引きたい場合は、Bからその抽象クラスをAに向けて実現し、その抽象クラスに対してAからの関連線を引くことを推奨している。Bからその抽象クラスへの依存線が、Aからの関連線とは逆向きになることが由来である。ここでの依存線は抽象クラスの生成を意味し、関連線はメソッドの呼び出しを意味する。
 
; [[デザインパターン (ソフトウェア)|GOFデザインパターン]]
: (''Gang of Four Design Patterns'')はソフトウェア開発において直面しやすい共通的かつ代表的なデザイン問題をピックアップし、それぞれの解決に最適なクラスパターン図を提示したものである。1994年から四人の計算機科学者ないしソフトウェア技術者たち(Gang of Four)によって発表され、OOPのデザインパターンの代表格と見なされた。教科書の内容としても取り上げやすい形式化されたトピックであったためにオブジェクト指向の学習面では非常に重視された。5個の生成パターン、7個の構造パターン、11個の振る舞いパターンに分類されている。
: 生成に関するパターン<gallery heights="40">
ファイル:Abstract Factory UML class diagram.svg|[[Abstract Factory パターン|Abstract factory]]
231 ⟶ 237行目:
ファイル:Mediator design pattern.png|[[Mediator パターン|Mediator]]
ファイル:Memento design pattern.png|[[Memento パターン|Memento]]
ファイル:Observer UML smal.png|[[Observer パターン|Observer]]
ファイル:State Design Pattern UML Class Diagram.svg|[[State パターン|State]]
ファイル:StrategyPatternStrategy Pattern in UML.png|[[Strategy パターン|Strategy]]
ファイル:Template Method UML class diagram.svg|[[Template Method パターン|Template Method]]
ファイル:Visitor UML class diagram.svg|[[Visitor パターン|Visitor]]
</gallery>
 
== 脚注 ==
{{脚注ヘルプ}}