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

C++、Java、Pythonなど、多くの一般的なプログラミング言語はOOPを採用しています。かつてはOOPは広く受け入れられていましたが[ 61 ]、最近では一部のプログラマーがOOPを批判し、関数型プログラミングを好むようになっています[ 62 ]。Potokらによる研究では、OOPと手続き型プログラミングの生産性に大きな違いは見られませんでした[ 63 ] 。
OOPはアルゴリズムやデータ構造よりもオブジェクトの使用に重点を置きすぎていると考える人もいます。[ 64 ] [ 65 ]例えば、プログラマーのRob Pikeは、OOPはプログラマーに型の構成よりも型の階層について考えさせる可能性があると指摘しました。[ 66 ]彼はOOPを「コンピューティングのローマ数字」と呼んでいます。[ 67 ] Clojureの作者であるRich Hickeyは、OOPは過度に単純化されており、特に時間の経過とともに変化する現実世界のものを表現する際にはそれが顕著だと述べています。[ 65 ] Alexander Stepanovは、OOPはすべてを単一の型に当てはめようとするため、制約が生じる可能性があると述べています。Stepanovは、ジェネリックプログラミングのように、複数の型にまたがるインターフェースのファミリーであるマルチソート代数が必要になる場合もあると主張しました。Stepanovはまた、すべてを「オブジェクト」と呼ぶことは理解を深める上であまり役に立たないと述べています。[ 64 ]
OOPはコードの再利用と保守を容易にするために開発されました。[ 68 ]しかし、プログラムの命令の流れを明確に示すようには設計されていませんでした。それはコンパイラに委ねられていました。コンピュータが並列処理やマルチスレッドを使用するようになると、命令の流れを理解し制御することがより重要になりました。これはOOPでは困難です。[ 69 ] [ 70 ] [ 71 ] [ 72 ]
著名なコンピュータ科学者であるポール・グレアムは、大企業がOOPを好むのは、平均的なプログラマーからなる大規模なチームの管理が容易になるからだと考えている。グレアムは、OOPは構造化することで一人のプログラマーが重大なミスを犯しにくくする一方で、優秀なプログラマーの能力を制限してしまうと主張している。 [ 73 ] Unixプログラマーでありオープンソースソフトウェアの提唱者であるエリック・S・レイモンドは、OOPはプログラムを書くための最良の方法ではないと主張している。[ 36 ]
リチャード・フェルドマンは、OOPの機能は一部の言語の体系化に役立ったが、その人気は他の理由から来ていると述べています。[ 74 ]ローレンス・クルブナーは、OOPは関数型プログラミングなどの他のスタイルと比較して特別な利点を提供しておらず、コーディングを複雑にする可能性があると主張しています。[ 75 ]ルカ・カルデッリは、OOPは手続き型プログラミングよりも遅く、コンパイルに時間がかかると述べています。[ 34 ]
。MITのローカルな方言では、連想リスト(原子記号)は「プロパティリスト」とも呼ばれ、原子記号は「オブジェクト」と呼ばれることもあります。
オブジェクト – 原子記号の同義語
{{cite book}}:ISBN / 日付の非互換性(ヘルプ){{cite web}}: CS1 maint: url-status (リンク){{cite news}}: CS1 maint: url-status (リンク)には型とメソッドがあり、オブジェクト指向のプログラミングスタイルが可能ですが、型階層はありません。
{{cite web}}: CS1 maint: url-status (リンク)ポリモーフィズム – 異なる型のエンティティに対して単一のインターフェースを提供すること。
{{cite web}}: CS1 maint: url-status (リンク)オブジェクト指向開発アプローチの最大の強みは、現実世界のモデルを捉えるメカニズムを提供していることです。
オブジェクト指向プログラミングは広く受け入れられているプログラミングパラダイムである