
オブジェクト指向プログラミング(OOP)は、オブジェクト[1](データと関数をカプセル化するソフトウェアエンティティ)に基づいたプログラミングパラダイムです。OOPコンピュータプログラムは、相互に相互作用するオブジェクトで構成されます。[2] [3] OOP機能を提供するプログラミング言語はOOP言語に分類されますが、OOPに貢献する機能のセットが議論されているため、言語をOOPとして分類すること、および言語がOOPをサポートする程度、またはOOPである程度は議論の余地があります。パラダイムは相互に排他的ではないため、言語はマルチパラダイムになる可能性があり、OOP以外のものに分類されることもあります。
オブジェクトは、現実世界の物やプロセスをデジタル形式で表現する場合があります。[4]たとえば、グラフィックスプログラムには、、、などのオブジェクトが含まれる場合がありますcircle。squareオンラインmenuショッピングシステムにはshopping cart、、、、customerなどのオブジェクトが含まれる場合がありますproduct。ニクラウス・ヴィルトは、「このパラダイム[OOP]は現実世界のシステムの構造を密接に反映しているため、複雑な動作をする複雑なシステムをモデル化するのに適しています」と述べています。[5]
しかし、多くの場合、オブジェクトは開いているファイルや単位変換器のような抽象的な実体を表します。OOPによって現実世界を正確にコピーすることが容易になる、あるいはそれが必要だという考えに、誰もが賛同するわけではありません。ボブ・マーティンは、クラスはソフトウェアであるため、クラスの関係はそれらが表す現実世界の関係とは一致しないと主張しています。[6] バートランド・マイヤーは、プログラムは世界のモデルではなく、世界の一部のモデルであると主張しています。「現実は二度離れたいとこ同士である」と。[7] スティーブ・イェッゲは、自然言語には関数型プログラミングのように、動作(メソッド)の前に物(オブジェクト)に名前を付けるというOOPのアプローチが欠けていると指摘しました。[8]このため、OOPソリューションは手続き型プログラミングで書かれたソリューションよりも複雑になる可能性があります。[9]
OOPをサポートする注目すべき言語には、Ada、ActionScript、C++、Common Lisp、C#、Dart、Eiffel、Fortran 2003、Haxe、Java、[10] JavaScript、Kotlin、Logo、MATLAB、Objective-C、Object Pascal、Perl、PHP、Python、R、Raku、Ruby、Scala、SIMSCRIPT、Simula、Smalltalk、Swift 、 Vala、Visual Basic (.NET)などがあります。
プログラミングにおける「オブジェクト」という概念は、1950年代後半から1960年代初頭にかけて、マサチューセッツ工科大学(MIT)の人工知能グループによって提唱されました。ここで「オブジェクト」とは、特定のプロパティ(属性)を持つLISPのアトムを指していました。 [11] [12] もう一つの初期の例として、 1960年から1961年にかけてMITでIvan Sutherlandが作成したSketchpadが挙げられます。Sutherlandは技術報告書の用語集で、「オブジェクト」や「インスタンス」(クラス概念は「マスター」または「定義」でカバー)といった用語を定義しましたが、これはグラフィカルなインタラクションに特化されていました。[13]その後、1968年には、MIT版ALGOLプログラミング言語であるAED-0が、データ構造(「プレックス」)とプロシージャを結び付け、後に「メッセージ」、「メソッド」、「メンバー関数」と呼ばれるようになるものの先駆けとなりました。[14] [15]データ抽象化やモジュラープログラミング といった話題は、当時よく議論されていました。
一方、ノルウェーでは1961年から1967年にかけてSimulaが開発されました。 [14] Simulaは、クラス、継承、動的バインディングといったオブジェクト指向の基本的な考え方を導入しました。[16] Simulaは主に、貨物港を通る船舶とその内容物の動きのような物理モデリング に携わる研究者によって使用されました。 [16] Simulaは、オブジェクト指向言語の主要な機能とフレームワークを備えた最初の言語として一般的に認められています。[17]
私は、オブジェクトを生物細胞やネットワーク上の個々のコンピューターのように、メッセージでのみ通信できると考えていました(つまり、メッセージングはごく初期に登場しました。プログラミング言語でメッセージングを効率的に行う方法を理解するには、しばらく時間がかかりました)。
MITとSimulaの両方の影響を受け、アラン・ケイは1966年11月に独自のアイデアの開発に着手しました。彼は後に、影響力のあるOOP言語であるSmalltalkを開発しました。1967年には、ケイはすでに「オブジェクト指向プログラミング」という用語を会話の中で使用していました。[1] OOPの「父」と呼ばれることもありますが、[18]ケイは自身のアイデアはOOPの一般的な理解とは異なると述べており、コンピュータサイエンス界は彼の概念を採用しなかったことを示唆しています。[1]バーバラ・リスコフ が共著した1976年のMITのメモには、Simula 67、CLU、Alphardがオブジェクト指向言語として挙げられていますが、Smalltalkについては言及されていません。 [19]
1970年代、Smalltalkプログラミング言語の最初のバージョンは、ゼロックスPARCでアラン・ケイ、ダン・インガルス、アデル・ゴールドバーグによって開発されました。Smalltalk-72は、言語レベルでのオブジェクトの使用とグラフィカルな開発環境で注目されました。[20] Smalltalkは完全に動的なシステムであり、ユーザーは作業中にクラスを作成および変更することができました。[21] OOPの理論の多くは、例えば多重継承など、Smalltalkの文脈で開発されました。[22]
1970年代後半から1980年代にかけて、OOPが注目を集めました。Flavorsオブジェクト指向Lispは1979年から開発され、多重継承とミックスインを導入しました。[23] 1981年8月、Byte MagazineはSmalltalkとOOPを特集し、これらのアイデアを幅広い読者に紹介しました[24] Interlisp -DのオブジェクトシステムであるLOOPSはSmalltalkとFlavorsの影響を受けており、1982年に論文が発表されました。[25] 1986年、オブジェクト指向プログラミング、システム、言語、アプリケーションに関する最初の会議(OOPSLA)には1,000人が参加しました。この会議は、Lispオブジェクトシステムを統合する取り組みの始まりを示し、最終的にCommon Lisp Object Systemにつながりました。1980年代には、メモリ内のオブジェクトのハードウェアサポートを含むプロセッサアーキテクチャを設計する試みがいくつかありましたが、これらは成功しませんでした。例としては、Intel iAPX 432とLinn Smart Rekursivがあります。
1980年代半ばには、Objective-C、C++、Eiffelといった新しいオブジェクト指向言語が登場しました。Objective-Cは、 ITT社でSmalltalkを使用していたBrad Coxによって開発されました。Bjarne Stroustrupは、博士論文でSimulaを使用した経験に基づいてC++を作成しました。 [20] Bertrand Meyerは1985年にEiffel言語の最初の設計を行いました。これは、契約による設計アプローチを用いてソフトウェアの品質に重点を置いたものでした。[26]
1990年代には、OOPがプログラミングの主流となり、特にVisual FoxPro 3.0、[27] [28] C++、[29] Delphi [要出典]などがサポートされるようになりました。OOPは、ボタン、メニュー、その他の要素にオブジェクトを使用するグラフィカルユーザーインターフェースの台頭により、さらに普及しました。よく知られている例としては、 macOSで使用され、 Objective-Cで記述されたAppleのCocoaフレームワークがあります。OOPツールキットは、イベント駆動型プログラミングの人気も高めました。[要出典]
ETHチューリッヒでは、ニクラウス・ヴィルトと彼の同僚たちがOOPへの新しいアプローチを生み出しました。Modula -2(1978年)とOberon(1987年)には、モジュール境界を越えたオブジェクト指向、クラス、型チェックへの独自のアプローチが含まれていました。ヴィルトの設計では、継承は明確ではありません。彼の命名法は逆方向を指しているためです。継承は型拡張と呼ばれ、視点は親から継承者へと下がっています。
OOPが普及する前に開発された多くのプログラミング言語は、 Ada、BASIC、Fortran、Pascal、COBOLなど、オブジェクト指向機能が追加されています。
言語によって提供されるOOP機能はさまざまです。以下は、OOP言語の一般的な機能です。[30] [31] [32] [33] OOPをリレーショナルプログラミングなどの他のスタイルと比較することは、OOPの明確で合意された定義がないため困難です。[34]
オブジェクトはフィールドとメソッドをカプセル化します 。フィールド(属性またはプロパティとも呼ばれます)は、情報(状態とも呼ばれます)を変数として保持します。メソッド(関数またはアクションとも呼ばれます)は、ロジックコードを介して動作を定義します。カプセル化とは、関連するコードをまとめることです。
情報の隠蔽とは、コードを必要とするコードだけがアクセスできるようにコードを整理することです。コードベースの残りの部分からはアクセスできません。オブジェクトの内部詳細は外部のコードから隠されているため、オブジェクトのインターフェースや他のコードに影響を与えることなく、オブジェクトの動作を変更できます。情報を隠蔽することで、コードを変更する際の問題を防ぐことができます。[35]オブジェクトは、内部の動作と外部の消費コードとの間の障壁として機能します。消費コードは、オブジェクトのパブリックメンバーを介してのみオブジェクトと対話できます
Javaのような一部のプログラミング言語は、可視性キーワード(privateとpublic)を介して情報の隠蔽を提供します。[36]可視性機能を提供しない言語もありますが、開発者はプライベートメンバー名をアンダースコアで始めるなどの規則に従う場合があります。Javaのprotectedキーワード(同じクラスとそのサブクラスからのアクセスは許可しますが、異なるクラスのオブジェクトからのアクセスは許可しません)や、internalC#、Swift、Kotlinのキーワード(同じモジュール内のファイルへのアクセスを制限します)など、中間レベルのアクセスも存在します。[37]
情報の隠蔽とデータ抽象化の支持者は、コードの再利用を容易にし、現実世界の状況を直感的に表現できると主張しています。[38] [39]しかし、OOPは可読性やモジュール性を向上させないと主張する人もいます。[40] [41] Eric S. Raymondは、 OOP言語は透明性を損なう階層化されたプログラムを奨励する傾向があると書いています。[42 ] Raymondはこれを、 UnixやC言語で採用されているアプローチと比較して不利な点があるとしています。 [42]
SOLIDにはオープン/クローズ原則が含まれており、クラスと関数は「拡張に対してはオープンであるべきであるが、変更に対してはクローズであるべき」とされています。ルカ・カルデッリは、OOP言語は「クラスの拡張と変更に関してモジュール性が非常に乏しい」ため、非常に複雑になりがちであると述べています。[40]後者の点は、 Erlangの主要な発明者であるジョー・アームストロングによって繰り返されており、次のように引用されています。[41]
オブジェクト指向言語の問題は、暗黙の環境を持ち歩いていることです。バナナが欲しかったのに、手に入れたのはバナナとジャングル全体を持ったゴリラでした。
レオ・ブロディは、情報の隠蔽はコードの重複につながる可能性があると述べています[43] 。これはソフトウェア開発の「同じことを繰り返さない」ルール[44]に反します。
オブジェクト合成により、オブジェクトは他のオブジェクトを含むことができます。例えば、オブジェクトはオブジェクトと、やなどの他の情報をEmployee含む場合があります。合成とは、「従業員は住所を持っている」といった「has-a」関係です。
Addressnameposition
継承はクラスまたはプロトタイプを介してサポートできます。これらは異なりますが、オブジェクトやインスタンスなどの類似した用語を使用します。
OOPの最も一般的なタイプであるクラスベースプログラミングでは、オブジェクトはクラスのインスタンスです。クラスはデータ(変数)とメソッド(ロジック)を定義します。オブジェクトはコンストラクターによって作成されます。クラスの要素には以下が含まれます。
クラスは他のクラスを継承し、クラスの階層構造を形成することがあります。これは、サブクラスがスーパークラスから継承する場合です。たとえば、クラスはEmployeeオブジェクトに変数を付与するクラスEmployeeから継承する場合があります。サブクラスは、スーパークラスに影響を与えない変数やメソッドを追加できます。ほとんどの言語では、サブクラスがスーパークラスのメソッドをオーバーライドすることもできます。一部の言語では多重継承をサポートしており、クラスは複数のクラスから継承できます。また、他の言語では同様にミックスインやトレイトをサポートしています。たとえば、UnicodeConversionMixinというミックスインは、FileReaderクラスとWebPageScraperクラスの両方にメソッドunicode_to_ascii()を追加する場合があります。
PersonPerson
抽象クラスはオブジェクトとして直接インスタンス化することはできません。スーパークラスとしてのみ使用されます。
その他のクラスは、クラス変数とメソッドのみを含み、インスタンス化やサブクラス化を意図していないユーティリティクラスです。[45]
プロトタイプベースプログラミングでは、クラスの概念を提供する代わりに、オブジェクトはプロトタイプまたは親と呼ばれる別のオブジェクトにリンクされます。Selfでは、オブジェクトは複数の親を持つことも、親を持たないこともありますが[46]、最も一般的なプロトタイプベース言語であるJavaScriptでは、オブジェクトはプロトタイプがnullであるベースオブジェクトまでのプロトタイプリンクを1つだけ持ちます。
プロトタイプは新しいオブジェクトのモデルとして機能します。たとえば、オブジェクトがある場合、プロトタイプの特性を共有する2つのオブジェクトとfruitを作成できます。プロトタイプベース言語では、オブジェクトが独自のプロパティを持つこともできるため、オブジェクトは属性を持つことができますが、オブジェクトやオブジェクトは属性を持ちません。
appleorangefruitapplesugar_contentorangefruit
Goのような一部の言語は継承をサポートしていません。[47]代わりに、オブジェクトは親子関係ではなく小さな部分を使用して構築される「継承よりも構成」を推奨しています。たとえば、EmployeeクラスはPersonクラスを継承する代わりに、Personオブジェクトを単に含むことができます。これにより、EmployeeクラスはPersonをプログラムの他の部分にどの程度公開するかを制御できます。委譲は、継承の代替として使用できるもう1つの言語機能です。
プログラマーは継承についてさまざまな意見を持っています。C++の作者であるBjarne Stroustrupは、継承なしでOOPを行うことが可能であると述べています。[48] Rob Pikeは、継承がより単純な解決策ではなく複雑な階層を作成するとして批判しています。[49]
あるクラスが別のクラスを継承する場合、サブクラスは元のクラスのより具体的なバージョンであると考える人がよくいます。これは、サブクラスのオブジェクトは常に元のクラスのオブジェクトを問題なく置き換えることができるというプログラムセマンティクスを前提としています。 この概念は、振る舞いサブタイピング、より具体的にはリスコフの置換原則として知られています
しかし、これは多くの場合当てはまりません。特に、作成後に変化する可変オブジェクト(変更可能なオブジェクト)を許可するプログラミング言語では顕著です。実際、OOP言語の型チェッカーによって強制されるサブタイプ多態性は、すべてのコンテキストではないにしても、ほとんどのコンテキストにおいて動作サブタイプを保証することはできません。例えば、円と楕円の問題は、 OOPの継承の概念を使用して処理するのが非常に難しいことで知られています。動作サブタイプは一般に決定不可能であるため、コンパイラによって簡単に実装することはできません。そのため、プログラマーはプログラミング言語自体が検出できないミスを避けるために、クラス階層を慎重に設計する必要があります。
メソッドは、コンパイル時ではなく実行時に選択されるように、動的ディスパッチを介して呼び出される場合があります。メソッドの選択が複数のタイプのオブジェクト(パラメータとして渡される他のオブジェクトなど)に依存する場合、多重ディスパッチと呼ばれます。
動的ディスパッチは継承と連携して機能します。オブジェクトに要求されたメソッドがない場合、親クラス(委任)を参照し、チェーンを遡って一致するメソッドを見つけます
メッセージパッシングとは、メソッド名とその入力がメッセージのようにオブジェクトに送信され、オブジェクトが処理することです。
ポリモーフィズムとは、サブタイピングまたはサブタイプポリモーフィズムを指します。これは、関数が特定のインターフェースと連携し、異なるクラスのエンティティを統一された方法で操作できることを意味します。[50]
たとえば、プログラムに円と四角形の2つの図形があるとします。どちらも「Shape」という共通クラスから来ています。それぞれの図形には独自の描画方法があります。サブタイプポリモーフィズムを使用すると、プログラムは各図形の型を知る必要がなく、各図形に対して「Draw」メソッドを呼び出すだけで済みます。プログラミング言語ランタイムは、各図形に対して正しいバージョンの「Draw」メソッドが実行されることを保証します。各図形の詳細は独自のクラス内で処理されるため、コードがよりシンプルで整理され、強力な関心の分離が可能になります。
オブジェクトのメソッドは、オブジェクトのデータにアクセスできます。多くのプログラミング言語では、現在のオブジェクトを参照するために、 や のような特別な単語を使用します。オープン再帰をサポートする言語ではthis、オブジェクト内のメソッドは、この特別な単語を使用して、同じオブジェクト内の他のメソッド(自身を含む)を呼び出すことができます。これにより、あるクラスのメソッドは、サブクラスで後で定義された別のメソッドを呼び出すことができます。これは遅延バインディングと呼ばれる機能です。
self
デザインパターンは、ソフトウェア設計における問題に対する一般的な解決策です。一部のデザインパターンはOOPに特に役立ち、通常はOOPのコンテキストで導入されます。
以下は、OOPオブジェクトの注目すべきソフトウェアデザインパターンです。[51]
operator())を持つクラス一般的なアンチパターンは、 Godオブジェクトです。これは、あまりにも多くのことを知っている、または多くのことを行うオブジェクトです。
『デザインパターン:再利用可能なオブジェクト指向ソフトウェアの要素』は、 1994年にErich Gamma、 Richard Helm、 Ralph Johnson、 John Vlissidesの4人の著者によって出版された有名な書籍です。彼らはしばしば「Gang of Four」と呼ばれます。この本は、OOPの長所と短所について述べ、プログラミングの問題を解決するための23の一般的な方法を説明しています。
これらのソリューションは「デザインパターン」と呼ばれ、3つのタイプに分類されます
OOPとリレーショナルデータベース管理システム(RDBMS)は、今日のソフトウェアで広く使用されています。しかし、リレーショナルデータベースはオブジェクトを直接保存しないため、両者を併用する際に課題が生じます。この問題は、オブジェクト・リレーショナル・インピーダンス・ミスマッチと呼ばれます。
この問題を解決するために、開発者はさまざまな方法を使用しますが、どれも完璧ではありません。[52]最も一般的な解決策の1つは、オブジェクト・リレーショナル・マッピング(ORM)です。これは、オブジェクト指向プログラムをリレーショナルデータベースに接続するのに役立ちます。ORMツールの例としては、Visual FoxPro、Java Data Objects、Ruby on Rails ActiveRecordなどがあります。
オブジェクトデータベースと呼ばれる一部のデータベースは、OOPで動作するように設計されています。しかし、リレーショナルデータベースほど普及しておらず、成功もしていません。
DateとDarwenは、RDBMSをサポートするための一種のカスタマイズ可能な型システムとしてOOPを使用する理論的基礎を提案しましたが、他のオブジェクトへのポインタを含むオブジェクトは禁止されています。[53]
責任駆動設計では、クラスは契約の形で、実行する必要がある処理と共有する情報を中心に構築されます。これは、クラスが保存する必要があるデータに基づいて構築されるデータ駆動設計とは異なります。責任駆動設計の創始者であるWirfs-BrockとWilkersonによると、責任駆動設計の方が優れたアプローチです。[54]
SOLIDは、Michael Feathersによって作成された、優れたソフトウェアを設計するための5つのルールのセットです。
GRASP (一般責任割り当てソフトウェアパターン)は、クレイグ・ラーマンによって作成されたソフトウェア設計ルールのもう1つのセットで、開発者がプログラムのさまざまな部分に責任を割り当てるのに役立ちます。[55]
研究者たちはOOPのセマンティクスを正式に定義しようと試みてきました。継承は困難を伴い、特にオープン再帰とカプセル化された状態との相互作用において困難を伴います。研究者たちは再帰型と余代数的データ型を用いてOOPの本質的な機能を組み込んできました。[56] AbadiとCardelliは、可変オブジェクトを扱うSystem F <:のいくつかの拡張を定義し、サブタイプ多態性とパラメトリック多態性(ジェネリクス)の両方を可能にし、多くのOOPの概念と構成要素を正式にモデル化することができました。[57] Javaなどのオブジェクト指向プログラミング言語の静的解析は、決して簡単ではありませんが、成熟した分野であり、[58]いくつかの商用ツールがあります。[59]
OOPはアルゴリズムやデータ構造よりもオブジェクトの使用に重点を置きすぎていると考える人もいます。[60] [61]例えば、プログラマーのRob Pikeは、OOPはプログラマーに型の構成よりも型の階層について考えさせる可能性があると指摘しました。[62]彼はOOPを「コンピューティングのローマ数字」と呼んでいます。[63] Clojureの作成者であるRich Hickeyは、特に時間の経過とともに変化する現実世界のものを表現する場合、OOPは過度に単純化されていると述べました。[61] Alexander Stepanovは、OOPはすべてを単一の型に当てはめようとするため、制限が生じる可能性があると述べました。彼は、ジェネリックプログラミングのように、複数の型にまたがるインターフェースのファミリーである、マルチソート代数が必要になる場合があると主張しました。Stepanovはまた、すべてを「オブジェクト」と呼んでも、理解があまり深まらないと述べました。[60]
OOPはコードの再利用と保守を容易にするために作成されました。[64]しかし、プログラムの命令の流れを明確に示すようには設計されていませんでした。それはコンパイラに委ねられていました。コンピュータが並列処理とマルチスレッドを使用するようになると、命令の流れを理解し制御することがより重要になりました。これはOOPでは困難です。[65] [66] [ 67] [68]
C++、Java、Pythonなど、多くの一般的なプログラミング言語はOOPを使用しています。かつてはOOPは広く受け入れられていましたが[69]、最近では一部のプログラマーがOOPを批判し、代わりに関数型プログラミングを好むようになっています。[70] Potokらによる研究では、OOPと他の手法の間に生産性に大きな違いは見られませんでした。[71]
著名なコンピュータ科学者であるポール・グレアムは、大企業がOOPを好むのは、平均的なプログラマーの大規模なチームの管理に役立つからだと考えています。彼は、OOPは構造を追加することで、一人のプログラマーが重大なミスを犯しにくくする一方で、優秀なプログラマーを抑制してしまうと主張しています。 [72] Unixプログラマーでありオープンソースソフトウェアの提唱者であるエリック・S・レイモンドは、OOPはプログラムを書くための最良の方法ではないと主張しています。[42]
リチャード・フェルドマンは、OOPの機能は一部の言語の体系性を維持するのに役立ったものの、その人気は他の理由から来ていると述べています。[73]ローレンス・クラブナーは、OOPは関数型プログラミングなどの他のスタイルと比較して特別な利点はなく、コーディングを複雑にする可能性があると主張しています。[74] ルカ・カルデッリは、OOPは手続き型プログラミングよりも遅く、コンパイルに時間がかかると述べています。[40]
オブジェクト指向開発アプローチの最大の強みは、現実世界のモデルを捉えるメカニズムを提供していることです。
。MITのローカルな方言では、[原子記号の]連想リストは「プロパティリスト」とも呼ばれ、原子記号は「オブジェクト」と呼ばれることもあります
オブジェクト – 原子記号の同義語
{{cite book}}: ISBN / Date incompatibility (help)
には型とメソッドがあり、オブジェクト指向スタイルのプログラミングが可能ですが、型階層はありません。
ポリモーフィズム – 異なる型のエンティティに単一のインターフェースを提供すること。
オブジェクト指向プログラミングは広く受け入れられているプログラミングパラダイムです