オブジェクト指向プログラミングの利点[終了]


35

:この質問は、数か月前に書いたブログ投稿からの編集された抜粋です。Programmers.SEのコメントにブログへのリンクを配置した後、回答できるように、誰かがここに質問を投稿するようにリクエストしました。人々がグーグルに「私はオブジェクト指向プログラミングを得ることはありません」と入力するように見えるので、この投稿は、私の最も人気のある多くのことを。こちら、またはWordpressのコメントでお気軽にお答えください。

オブジェクト指向プログラミングとは何ですか?誰も満足のいく答えをくれませんでした。鼻を空中に置いて「オブジェクト」や「オブジェクト指向」と言って回る人からは、良い定義が得られないと感じています。また、オブジェクト指向プログラミング以外は何もしていない人から良い定義を得ることもできません。手続き型プログラミングとオブジェクト指向プログラミングの両方を理解している人は誰も、オブジェクト指向プログラムが実際に何をするのかについて一貫した考えを私に与えたことはありません。

誰かがオブジェクト指向プログラミングの利点についてのアイデアを教えてください。


2
ああ、いいですね。OOPを行うと言う人全員が同意する定義を考え出すのは難しいです。(例:OOP衣服での手続き型プログラミングを実際に行っている人を無視した場合でも。)
SamB

10
「Cプログラミングを習得していません。アセンブリ言語だけを使用することはできませんか?」私に。
tia

2
@ジョエル:私はあなたと同じ情報のない支持者を必ずしも知っているわけではありませんが、その大部分はOO言語のクラスによってプログラミングに導入されたかもしれないと思います。それがベースラインである場合、それがどのようにステップアップするか理解できません。私の最初の言語はApplesoft BASICで、DelphiとC ++でOOPを紹介される前に、いくつかのBASIC方言、C、Pascal、およびx86アセンブリを少し学びました。違いを経験した人々はそれをよりよく説明できます。
メイソンウィーラー

3
OOPについてのより否定的なコメントは、ここで:DiykstraとRob Pikeからの引用を含め、rious.cat-v.org / software / OO_programmingです。
imgx64

3
@ジョエル:あなたは頭でOOPに私の反対を打った。OOPの真の道筋である人々は、通常、手続き型プログラミングのstraw見を持ち、他のパラダイムの経験はほとんど、またはまったくありません。関数型プログラミングはまったく異質に見えます(証拠:奇妙な理由で最近Erlangでクラスやオブジェクトを行う方法を尋ねる人々の数を数えます)。私は実際に奇妙なパラダイムの一部が....彼らにどうなるのか想像することができます
JUST MY正しい意見

回答:


7

ソフトウェアは、コンピューター内部に存在する機械または組立ラインと考えてください。一部の原材料およびコンポーネントは機械に供給され、一連の手順に従って最終製品に加工されます。これらの手順は、特定の順序で特定のパラメーターセット(時間、温度、距離など)に対して特定の操作を実行するように設定されています。実行する操作の詳細が正しくない場合、機械のセンサーが正しく較正されていない場合、または一部の原材料またはコンポーネントが期待される品質基準内にない場合、操作の結果が変わる可能性があり、製品は判明しません予想通り。

このようなマシンは、その操作と許容可能な入力が非常に硬直しています。機械は、設計者の知性や現在の動作環境に疑問を投げかけません。指示されている限り、手順に従い続けます。原材料やコンポーネントの変更が後の操作で起こったことに劇的な影響を与える可能性がある場合でも、マシンはその手順を実行します。プロセスを見直して、目的の結果を補正し生成するために手順の変更が必要かどうかを確認する必要があります。製品の設計または構成を変更するには、実行する操作またはその順序を大幅に変更する必要がある場合があります。生産担当者は、業務間の望ましくない影響を減らすために、できる限り業務を分離することの重要性をすぐに学びましたが、処理が行われる際に、コンポーネントが存在する条件について多くの仮定が行われます。いくつかの異なるオペレーティング環境で最終製品がユーザーの手に渡るまで検出されないかもしれない仮定。

それが手続き型プログラミングのようなものです。

オブジェクト指向が提供するのは、コンポーネントの状態の仮定を取り除く方法です。したがって、そのコンポーネントで実行される操作と、それを最終製品に統合する方法。言い換えれば、OOPは特定のコンポーネントを処理するためにプロセスの詳細を取得し、それをより小さなマシンに提供するようなものです。プロセスを担当する大規模なマシンは、コンポーネント固有のマシンにどの操作を実行する予定かを伝えますが、ステップの詳細はコンポーネント固有のマシンに任せて処理します。

非オブジェクト指向ソフトウェアに対するオブジェクト指向の利点に関して:

  • コンポーネント固有の動作 -特定のコンポーネントを処理する方法の詳細をコンポーネント固有の小さなマシンの責任にすると、コンポーネントが処理されるときはいつでも、マシンは適切に処理します。
  • ポリモーフィック式 -コンポーネント固有のマシンは特定のコンポーネントに合わせた操作を実行するため、異なるマシンに送信された同じメッセージは異なる動作をする可能性があります。
  • 型の抽象化 -いくつかの異なるタイプのコンポーネントがマシンの操作に同じ語彙を使用することはしばしば理にかなっています。
  • 懸念事項の分離 -コンポーネント固有の詳細をマシンに任せることは、プロセスマシンが、プロセスとそれを管理するために必要なデータのより一般的で大きな懸念事項を処理するだけでよいことを意味します。さらに、他のコンポーネントの変更による影響を受けにくい。
  • 適応性 -専門分野に焦点を合わせたコンポーネントは、使用するコンポーネントを変更するか、別のプロセスマシンで使用できるようにするだけで、予期しない使用に適応させることができます。
  • コードの再利用 -焦点が狭く適応性が高いコンポーネントは、より頻繁に使用されるため、開発コストを活用できます。

3
あなたが言ったことはすべて、関数型プログラミングにも同様に当てはまるようで、ここで問題を強調しています。
ジェシーミリカン

1
OPが関数型プログラミングについて尋ねなかったのを除けば、コメントにはメリットがありません。特に私の答えは受け入れられたものだからです。
Huperniketes

関数型プログラミングは当然オブジェクト指向に近いものです。実際、関数型プログラミングは実際には、関数自体がファーストクラスのオブジェクトになる、より純粋なオブジェクト指向の形式であると主張できます。それでも、関数型プログラミングのすべての分野での初心者ですが、それでも、現時点では私にとってどのような感じですか。
ニュートピア

46

あなたのブログからは、命令型プログラミングと関数型プログラミングの両方に精通しており、オブジェクト指向プログラミングに関連する基本概念に精通しているようですが、実際に「クリック」したことはありません。便利になります。私はその知識の観点から説明しようとし、それがあなたに役立つことを願っています。

OOPは、本質的に、命令型パラダイムを使用して、問題の領域をモデル化する「スマート」データ構造を作成することにより、高度な複雑さをより適切に管理する方法です。(標準の手続き型の非オブジェクト指向)プログラムには、2つの基本的なものがあります。変数と、それらをどう処理するかを知っているコードです。このコードは、ユーザーおよびその他のさまざまなソースからの入力を受け取り、変数に格納して操作し、ユーザーまたはその他のさまざまな場所に送られる出力データを生成します。

オブジェクト指向プログラミングは、その基本的なパターンを採用して小規模で繰り返すことにより、プログラムを簡素化する方法です。プログラムが何をすべきかを知っているコードを備えた大量のデータの集まりであるように、各オブジェクトは何をすべきかを知っているコードにバインドされた小さなデータです。

問題の領域をより小さな部分に分割し、可能な限り多くのデータを、それをどう処理するかを知っているコードに直接バインドすることにより、プロセス全体およびサブプロセスについて推論することがはるかに容易になります。プロセスを構成する問題。

データをオブジェクトクラスにグループ化することにより、そのデータに関連するコードを集中化して、関連するコードを見つけやすく、デバッグしやすくすることができます。また、アクセス指定子の背後にあるデータをカプセル化し、メソッド(または言語がサポートしている場合はプロパティ)を介してのみアクセスすることにより、データ破損や不変条件の違反の可能性を大幅に減らします。

また、継承とポリモーフィズムを使用することで、既存のクラスを再利用し、特定のニーズに合わせてカスタマイズすることができます。元のクラスを変更したり、ゼロからすべてを書き換えたりする必要はありません。(これはあなたがやるべきではありません事、あなたがそれを避けることができれば、。)ちょうどあなたがあなたのベースオブジェクトを理解するか、で終わる可能性があり注意が必要キラーカンガルー

私にとって、これらはオブジェクト指向プログラミングの基本原則です。複雑さの管理、コードの集中化、オブジェクトクラスの作成による改善された問題領域モデリング、継承とポリモーフィズム、カプセル化とプロパティ。これが、なぜ多くのプログラマーが便利であると考えるのかを理解するのに役立つことを願っています。

編集:コメントでのジョエルの質問に答えて、

命令型プログラムとは根本的に異なる「オブジェクト指向プログラム」に含まれる内容(説明したこれらの派手な定義以外)を説明できますか?「ボールを転がす」方法

ここで少し免責事項。「オブジェクト指向プログラム」の私のモデルは基本的にDelphiモデルで、元のDelphiチームメンバーによって作成されたため、C#/。NETモデルに非常に似ています。私がここで言っていることは、他のオブジェクト指向言語には当てはまらないか、それほど当てはまらないかもしれません。

オブジェクト指向プログラムは、すべてのロジックがオブジェクトを中心に構成されているプログラムです。もちろん、これはどこかにブートストラップする必要があります。典型的なDelphiプログラムには、と呼ばれるシングルトンオブジェクトを作成する初期化コードが含まれていますApplication。プログラムの開始時に、をApplication.Initialize呼び出してApplication.CreateFormから、最初からメモリにロードするすべてのフォームの呼び出しを行いApplication.Run,、画面にメインフォームを表示し、すべてのコアを形成する入力/イベントループを開始しますインタラクティブなコンピュータープログラム。

アプリケーションとフォームは、OSからの着信イベントをポーリングし、オブジェクトのメソッド呼び出しに変換します。非常に一般的なことの1つは、イベントハンドラーの使用、または.NETでの「デリゲート」です。オブジェクトには、「XとYを実行するだけでなく、この特定のイベントハンドラーが割り当てられているかどうかを確認し、割り当てられている場合は呼び出します」というメソッドがあります。イベントハンドラーは、オブジェクトへの動作を拡張するために使用されるメソッドポインター(メソッドへの参照とオブジェクトインスタンスへの参照を含む非常に単純なクロージャー)です。たとえば、フォームにボタンオブジェクトがある場合、OnClickイベントハンドラをアタッチすることで動作をカスタマイズします。これにより、ボタンがクリックされたときに他のオブジェクトがメソッドを実行します。

そのため、オブジェクト指向プログラムでは、メソッドポインターを使用するか、あるオブジェクトが別のオブジェクトのパブリックインターフェイスで定義されたメソッドを直接呼び出すことにより、特定の責任を持つオブジェクトを定義してリンクすることにより、ほとんどの作業が行われます。(そして今、私たちはカプセル化に戻りました。)これは、大学でOOPクラスを受講する前に、私が元に戻すという概念を持っていなかったという考えです。


4
あなたは本当にこの答えで頭に釘を打ったと思います。データ操作をカプセル化すると(OK、ここにポインタを割り当てて、そこに数ビットをシフトします...)残っているのはプログラムの高レベルロジックだけです(適切に行われれば、どんなパラダイムでも恐ろしいコードを書くことができます。)
ChaosPandion

2
それは素晴らしい説明です、ありがとう。命令型プログラムとは根本的に異なる「オブジェクト指向プログラム」に含まれる内容(説明したこれらの派手な定義以外)を説明できますか?「ボールを転がす」方法
ジョエルJ.アダムソン

1
+1:基本的には別のレベルの抽象化(または、抽象化を作成するための別の可能なレベルのような)で、「基本的には同じことを小規模で繰り返す」ことで本当に得たと思います。
n1ckp

1
@Karthikパーティーに少し遅れましたが、実際にはありません。OOPはクラスを再利用することを意味する必要はありません。型システムの概念全体は、共通のインターフェースの下でオブジェクトをグループ化するための抽象化です。ただし、オブジェクトのメソッド呼び出しがクラスチェーンではなくプロトタイプチェーンを解決するプロトタイプベースのシステム(Javascriptなど)を使用することもできます。OOPのすべての機能を引き続き備えていますが、既存のオブジェクトに新しいものを追加するだけで、アドホックオブジェクトと型を使用できます。その後、そのオブジェクトを複製して、新しいタイプをさらに取得できます。
CodexArcanum

2
+1は、OOPの真の利点を正確に示しています。「基本的に、OOPは命令型パラダイムを使用して、問題ドメインをモデル化する「スマート」データ構造を作成することにより、高度な複雑さをより適切に管理する方法です。」
Karthik Sreenivasan

6

OOPは基本的に、私がそうであったように、あなたが途中でやろうと思ったかもしれない何かに与えられた単なる名前だと思います。

私が赤ん坊のプログラマーだった頃、Fortranでさえ、サブルーチンへのポインターのようなものがありました。サブルーチンへのポインターを別のサブルーチンへの引数として渡すことができると本当に便利です。

次に、実際に役立つ次のことは、データ構造のレコード内にサブルーチンへのポインターを格納することです。そうすれば、レコードは自分自身で操作を行う方法を「知っている」と言うことができます。

彼らがそれをFortranに組み込んだかどうかはわかりませんが、Cとその子孫では簡単にできます。

そのため、下には、あなたが自分でやりたいと思ったかもしれないという単純で便利なアイデアであり、一部の人々がそれを怖い流行語でいっぱいの巨大な時流に変えたとしても、より新しい言語でより簡単に行うことができます。


5

OOシステムにはさまざまな種類があり、誰もが同意する定義を得るのは困難です。JavaのOOがCommon Lisp Object Systemにどのように似ているかを示すのではなく、少し慣習的なものから始めます。

散乱データとして存在する多くのオブジェクトがあるとします。たとえば、ポイントは、X、Y、Z配列の要素です。ポイント自体を考慮するためには、すべてのデータをCのようなものにまとめるのが理にかなっていますstruct

これで、任意のデータオブジェクトについて、データがすべて揃っています。ただし、手続き型プログラムでは、コードは散在しています。幾何学的な形状を扱っているとします。図形を描画するための大きな機能があり、すべての図形について知る必要があります。エリアを見つけるための大きな機能と、境界のための別の機能があります。円のコードは複数の関数に散在しており、別のタイプの形状を追加するには、どの関数を変更するかを知る必要があります。オブジェクト指向システムでは、関数をclassデータと同じ種類のもの()に収集します。したがって、すべてのサークルコードを確認したい場合はCircle定義にあり、a Quartercircleを追加したい場合はそのクラスを記述するだけでコードが得られます。

これの利点の1つは、クラスの各メンバーについて真実であるクラス不変式を維持できることです。クラスの外部のコードがクラスデータメンバーを直接操作しないように制限することで、クラスデータを1か所で変更できるすべてのコードを取得しました。他の2つの組み合わせよりも長い)。これは、クラスのすべてのメンバーのいくつかのプロパティに頼ることができ、オブジェクトを使用するたびに正気かどうかを確認する必要がないことを意味します。

主な利点は、継承とポリモーフィズムです。これらのさまざまな形状のすべてをというクラスのサブクラスとして定義することによりShape、コードを操作することができますShape。そして、形状サブオブジェクトの役割は、操作によって要求されることをすべて行うことです。これは、新しいシェイプを追加したり、古いシェイプの動作を改良したりするときに、テスト済みの古いコードに触れる必要がないことを意味します。新しいコードを直接利用できる古いコードが自動的に作成されます。制御コードに、考えられるすべての異なる形状を認識させ、考えられるすべての異なる形状を認識する機能を維持する代わりに、Shapeサブクラスを維持しながら、形状とそのプロパティを処理するだけです。これにより、制御コードが簡素化されます。

ここにはいくつかの利点があります。クラス不変式があるので、組み込みデータ型と同じように、より大きなデータオブジェクトについて推論できます。つまり、複雑な概念をより単純な概念に分割できることがよくあります。サークルコードの大部分はに含まれCircleているため、地域性が向上しています。異なる場所にあるいくつかの異なる関数に散らばる円の概念がないため、ルーチン間の結合が少なくなり、それらを同期させることを心配する必要がありません。クラスは実際には型であるため、既存の型システムを利用して、クラスの互換性のない使用をキャッチできます。


3

OOにはさまざまな定義があります、はい。あなたは自分でこれらの多くを見つけることができると確信しています。私は個人的にRees Re:OOがそれらを理解する方法として好きです。ポール・グラハムの言葉を引用してからすでに読んでいると思います。(OOに興味がある人にはお勧めします。)ここ{1,2,3,7,8,9}でJava定義を多かれ少なかれ採用するつもりです。

OOの有用性の問題、特に私がそれに取り組む方法については、数千行のコードではるかに大きな答えに値します(部分的には単なるアサーションではないため)。ただし、ここではその仮想文書の要約を示します。

オブジェクト指向は、小規模、たとえば数百行程度でひどく役立つとは思いません。特に、優れた機能的影響のないオブジェクト指向言語は、あらゆる種類のコレクションや多くのデータ型を必要とするもので簡単なことを行うのを本当に苦痛にさせる傾向があります。これは、ほとんどのデザインパターンが作用する場所です。それらは、基礎となる言語の低出力に関するバンドエイドです

約1000行で、すべての操作とデータ構造、およびそれらの関係を追跡するのが難しくなり始めています。この時点で、データ構造と操作を明示的に整理する方法、モジュールの境界を描き、責任を定義する方法、およびそれらに対して定義しようとしている間にそれらの定義を理解する便利な方法を持つことが役立ちます。

Java風のOOは、人気コンテストで優勝したこれらの問題の中間的な解決策です。これは、Javaの人々が力不足の言語によって作成された小規模な問題に適用するのと同じメカニズムであるため、単に整理された状態を維持する方法よりも、すべてに対する魔法の解決策のように見える傾向があります。関数型プログラミングに精通している人は、CLOSやHaskellの型クラス、C ++でスタックしている場合のテンプレートメタプログラミングなど、他のソリューションを好む傾向があります。 。


+1-すばらしい回答。「私は、オブジェクト指向が小規模ではひどく役立つとは思わない。」
カルティクスリーニバサン

私は、OOPがソフトウェア製品の最初の2つのリリースの手続きに対して実際の生産性の利点を示さないという記事(dl.acm.org/citation.cfm?id=326103)を読みました。私の知る限り、3番目のリリースからのみ、プロシージャルスタイルよりもオブジェクト指向スタイルで記述されたコードを再利用/リファクタリングできるため、真の利点があります。
ジョルジオ

1

OOPは、オブジェクトとそれらの間の相互作用の観点から現実世界の概念をモデル化しようとします。人間として、私たちはオブジェクトの観点から世界を処理する傾向があります。世界には特定のプロパティを持つオブジェクトがたくさんあり、他のオブジェクトとやり取りするようなことができます。OOPでは、同様の用語で世界をモデル化できます。例えば、

  • 人はオブジェクトです。人には、年齢や性別などのプロパティがあります。人は物事をすることができます:食べる、寝る、車を運転する。
  • 車もオブジェクトです(ただし、タイプは異なります)。また、make、model、yearなどのプロパティもあります。車は物事を行うことができます:移動。

しかし、車はそれ自体では移動できません。車を運転するには人が必要です-オブジェクト間の相互作用。


わかりました。それは理にかなっています。しかし、コンピューターのプログラミングで本当にクールなことの1つは、「現実の」オブジェクトがどのように物事を行うかという点で考える必要がないことだと思います。私はもっ​​と数学的に考えます(私は生物学の研究をしている数学者です)。これは「a-ha」(瞑想的な洞察)であり、態度ではありませんでした。しかし、それは私の仕事のやり方に大きく影響しました。
ジョエルJ.アダムソン

1

OOP =データ構造+メッセージパッシング+継承。これらはすべてプログラミングモデルの論理的な進化です。

OOPは(プログラマーによって)約90秒で理解できます(リンクについては私のプロファイルを参照してください)。コンセプトは非常にシンプルです。

それを適用する方法は別の問題です。ハンマーを振る方法を知っているからといって、家を設計し建設する方法を知っているわけではありません。;-)


+1-同意します。OOPの適用方法は多くの練習と時間を要しましたが、それらが何であるかを知っているだけでは、意味がここでのキーワードであるため、まったく時間がかかりませんでした。
カルティクスリーニバサン

0

少し前に、役に立つと思うブログ記事を書きました:手続き型とOOPの説明


なぜ人々が投票したのか分かりません!この記事は、上記のすべての記事をまとめたものよりも優れています!+1の投票
ハリス

ただリンクアンドランであるため、投票は拒否されました。metastackoverflowの質問を参照してください:他の場所にリンクを含むだけの回答は本当に「良い回答」ですか?
icc97

0

私が最初にそれを理解した方法は:

オブジェクト指向プログラミングの前には、構造化プログラミングがありました。すべてがプロセスに集中しています。自問自答した最初の質問は、「情報で何をしたいですか?」です。

オブジェクト指向プログラミングでは、データを中心にしています。自問自答した最初の質問は、「対処する必要がある魔女情報」です。これにより、抽象化が容易になります。


0

構造体を理解し、関数ポインターを理解し、関数ポインターを使用して構造体を理解しているので、あなたの観点から、オブジェクト指向プログラミングを単に「プログラミング、関数ポインターを持つ構造体を多用する」と定義します。それはまだ伝統的な意味でのプログラミングです-それはすべてのデータであり、データに作用するコードです。違いは、その情報のすべてがどのように定義されるかと、それをどのように定義するかということです。

おそらく、過度に単純化されているのは、従来のプログラミングは「コード、一部のデータ構造」であり、オブジェクト指向プログラミングは「データ構造、一部のコード」であるということです。どちらもまだデータ構造を持ち、両方はまだコードを持っています。オブジェクト指向プログラミングは、データの種類を事前に定義し、関数セットを介して通信する方法について契約を強制する行為にすぎません。

お気づきのように、ソリューションを実装するのにこれほど素晴らしい方法ではないアプリケーションの巨大なクラスがあります。そのようなアプリケーションで主に構成されている世界に住んでいるようです。ブログの投稿で、「99本のビール」問題(「お気に入りのプログラミングショーケース」)の実装について説明しています。99本のビールは確かにそのカテゴリーの一部です。99本のビールの実装を見ることでオブジェクト指向プログラミングを理解しようとすることは、ツリーハウスを見ることで高層建築を理解しようとすることに少し似ています。非常にうまく構築されたツリーハウスでさえ、あなただけを教えることができます。

TL; DR:オブジェクト指向プログラミングは従来のプログラミングと似ていますが、データ構造を事前に定義することにより多くの努力を集中し、それらのデータ構造を関数ポインターを介して互いに通信させる点が異なります。


-1

ウィキペディアのページは、基本を知るのに適した場所だと思います。http
//en.wikipedia.org/wiki/Object-oriented_programming

基本的には、OOPが改善しようとしている手続き型プログラミングは、モデル化されているプロセスに焦点を当てているという考え方です。OOPは、モデル化する「モノ」に焦点を合わせたモデルに移行し、それらのモノのプロセスとデータがそれらのモノに含まれます。

したがって、例として、タスクリストを追跡するアプリケーションを設計していたとしましょう。手続き型プログラミングでは、モデルの最上位エンティティは、タスクの作成、タスクの削除、タスク情報の変更など、発生するプロセスになります。OOPモデルでは、代わりにタスクの作成に集中します。そのタスクが担当するデータとプロセスを考えます。そして、タスクについてのメモを保持したい場合は、メモや何かなど、タスクが操作する他のオブジェクトに焦点を当てます。

それがお役に立てば幸いです。読み続けてコードを見るだけで、突然「クリック」します。それが私の経験でした。


理由を述べるためのダウンボッターのケア?
RationalGeek

質問全体を読んでいない可能性が高いようです。リンクされたブログエントリにはあまり触れていません。私が知る限り、著者はファンダメンタルズに問題はありません。だから、基本的には、-1の質問に答えるために、あなたは質問ビーイングが尋ねたのではなく答えることを望んでいました。
ジェシーミリカン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.