[編集:]以前、私はこれを、いつOOPを使用するか、いつ手続き型プログラミングを使用するかについて、おそらくフレームが不十分な質問として質問しました。それどころか、私はOOPをよく使用しましたが、手続き型アプローチをいつ使用するかを知りたいと思います。回答から判断すると、OOPは通常、より優れたオールラウンドなアプローチであるが、OOPアーキテクチャが必要な場合は手続き型言語を使用する必要があるという、かなり強いコンセンサスがあると思います。長期的には再利用のメリットはありません。
しかし、Javaプログラマーとしての私の経験はそうではありませんでした。私が設計した大規模なJavaプログラムは、私が書いたコードの1/10で、Perlの第一人者によって書き直され、OOP完全性のモデルと同じくらい堅牢に見えました。私のアーキテクチャではかなりの量の再利用が見られましたが、より簡潔な手続き型アプローチによって優れたソリューションが生み出されました。
ですから、繰り返すリスクを冒して、オブジェクト指向のアプローチよりも手続き型をどのような状況で選択すべきか疑問に思っています。 OOPアーキテクチャがやり過ぎであり、手続き型アプローチがより簡潔で効率的である可能性が高い状況を事前にどのように特定しますか。
それらのシナリオがどのように見えるかの例を誰かが提案できますか?
手続き型プログラミングアプローチによってより適切に提供されるプロジェクトを事前に特定するための良い方法は何ですか?
特定の問題に対して見つけることができる最も簡潔な標準ベースのアプローチを使用することをお勧めします。 Perlを使用した同僚は、特定のツールをよく知っている優れた開発者が、方法論に関係なく優れた結果を達成できることを実証しました。手続き型とOOPの議論の良い例として、JavaとPerlのプロジェクトを比較するのではなく、PerlとRubyなどの同様に簡潔な言語との対決を見てみたいと思います。オブジェクト指向の。今、それは私が見たいものです。私の推測では、Rubyが一番上に出てくるでしょうが、ここで言語の炎上戦争を引き起こすことに興味はありません-私のポイントは、あなたが仕事に適切なツールを選択することだけです-どんなアプローチでもタスクを達成できます可能な限り最も効率的で堅牢な方法で。 Javaはオブジェクト指向のために堅牢かもしれませんが、あなたとあなたの同僚、そしてRubyやPythonなどの動的言語に変換している他の多くの人がこれらを見つけています数日、手続き型であろうとOOPであろうと、はるかに効率的なソリューションがあります。
私は Glass ' 再利用に関しては3のルールが好きです(これはあなたが興味を持っているようです)。
1)再利用可能なコンポーネントの構築はシングルユースコンポーネントの3倍困難です
2)再利用可能なコンポーネントは、再利用ライブラリに受け入れるのに十分一般になる前に、3つの異なるアプリケーションで試してみる必要があります。
これから、これらの結果を推定できると思います
a)1回限りのコンポーネントを構築するのにかかる時間の3倍の予算がない場合は、再利用を控える必要があります。 (難易度=時間と仮定)
b)作成するコンポーネントを使用する場所が3つない場合は、再利用可能なコンポーネントの作成を延期する必要があります。
OOPは、後で本当に再利用可能なものにいつでもリファクタリングできるため、シングルユースコンポーネントの構築に役立つと思います。 (PPからOOPにリファクタリングすることもできますが、OOPには、そこから開始するための編成とカプセル化に関して十分な利点があると思います)
再利用性(またはその欠如)は、特定のプログラミングパラダイムに拘束されません。必要に応じて、オブジェクト指向、手続き型、関数型、またはその他のプログラミングを使用します。整理と再利用性は、ツールからではなく、あなたが行うことから生まれます。
あなたは自分で答えを出しました-大きなプロジェクトは、乱雑になりすぎないようにするためにOOPが必要です。
私の見解では、OOPの最大の利点はコード編成です。これには、DRYとカプセル化の原則が含まれます。
OOPを宗教的に支持する人々は、これらのコメントにも見られるように、支持を正当化する事実を持っていません。彼らは大学でOOPとOOPのみを使用して賞賛するように訓練されている(または洗脳されている)ので、盲目的にそれをサポートしています。彼らはPPで実際の仕事をしたことがありますか?チーム環境で不注意なプログラマーからコードを保護する以外に、OOPはあまり提供しません。 PPとOOPの両方で何年も個人的に働いていると、PPはシンプルでわかりやすく、より効率的であることがわかりました。私は次の賢者に同意します。女性:
(参照: http://en.wikipedia.org/wiki/Object-directiond_programming ):
多くの有名な研究者やプログラマーがOOPを批判しています。不完全なリストは次のとおりです。
Luca Cardelliは、「 オブジェクト指向言語の悪いエンジニアリングプロパティ 」というタイトルの論文を書きました。
リチャード・ストールマンは1995年に次のように書いています。「EmacsにOOPを追加することは明らかに改善ではありません。 LISPマシンウィンドウシステムで作業するときにOOPを使用しましたが、これがプログラミングの優れた方法であるという通常の見方に同意しません。」
Potokらによる研究。 OOPと手続き型アプローチの間で生産性に有意差は見られませんでした。
Christopher J. Dateは、OOPを他のテクノロジー、特にリレーショナルと批判的に比較することは、OOPの合意された厳密な定義がないため、難しいと述べました。 RDBMSをサポートするためのカスタマイズ可能な型システムの一種としてOOPを使用する、OOPの理論的基盤が提案されています。
アレクサンダーステパノフは、OOPが数学的に制限された視点を提供することを提案し、それを「人工知能とほぼ同じくらいのデマ」と呼びました(おそらく、人工知能プロジェクトと1980年代のマーケティングを指します。振り返ってみると)。
Paul Grahamは、OOPの目的は、平凡な組織の平凡なプログラマーが「過度の損害を与える」ことを防ぐ「放牧メカニズム」として機能することであると示唆しています。これは、より強力でよりコンパクトな手法の使用方法を知っている生産的なプログラマーの速度を低下させるという犠牲を払っています。
Erlangの主な発明者であるJoeArmstrongは、次のように述べています。「オブジェクト指向言語の問題は、オブジェクト指向言語が持ち歩く暗黙の環境をすべて備えていることです。あなたはバナナが欲しかったのですが、あなたが手に入れたのはバナナとジャングル全体を持ったゴリラでした。」
COMPUTEの著者で元編集者のRichardMansfield!雑誌は、「長年にわたる他の無数の知的流行(「関連性」、共産主義、「モダニズム」など-歴史はそれらに散らばっています)のように、OOPは最終的に現実が主張するまで私たちと一緒にいると述べています自体。しかし、OOPが現在大学と職場の両方にどのように浸透しているかを考えると、OOPは永続的な妄想であることがわかるかもしれません。教化されたプログラマーの世代全体がアカデミーを去り続け、彼らの残りの人生の間、OOPとOOP以外の何物でもありません。」また、「OOPはプログラムを作成することであり、空港のセキュリティを通過することは飛行することです」と述べているとも言われています。
DRY原則(Do n't Repeat Yourself)と少しのアジャイルを組み合わせたものが良いアプローチだと思います。動作する最も単純なものから始めてプログラムを段階的に構築し、機能を1つずつ追加して再-必要に応じてコードを因数分解します。
同じ数行のコードを何度も(おそらく異なるデータで)書いていることに気付いた場合は、変更されたものと同じままのものを区別するのに役立つ抽象化について考えるときが来ました。
自信を持ってリファクタリングできるように、反復ごとに徹底的な単体テストを作成します。
コードのどの部分を再利用可能にする必要があるかを予測するのに多くの時間を費やすのは間違いです。システムのサイズが大きくなり始めると、すぐに明らかになります。
複数の同時開発チームが存在する大規模なプロジェクトの場合、開発をガイドするための何らかのアーキテクチャ計画が必要ですが、自分で作業している場合、または小規模な協力チームで作業している場合は、DRY原則。
このアプローチのもう1つの利点は、実際の経験に基づいて行うことです。私のお気に入りの例え-建物がどのように建設されるかを想像する前に、レンガで遊ぶ必要があります。
非常に明確に指定された問題、仕様変更されないがあり、非常に高速を実行したい場合は、手続き型スタイルを使用する必要があると思います。そのためのプログラム。この場合、保守性とパフォーマンスを交換することができます。
通常、これは、ゲームエンジンまたは科学シミュレーションプログラムを作成する場合に当てはまります。 -)。プログラムが1秒間に100万回を超える計算を行う場合は、Edgeに最適化する必要があります。
非常に効率的なアルゴリズムを使用できますが、キャッシュの使用を最適化するまでは十分な速度にはなりません。データがキャッシュされることで、パフォーマンスが大幅に向上する可能性があります。これは、CPUがRAMからバイトをフェッチする必要がないことを意味します。これを実現するには、データを互いに近くに格納し、実行可能ファイルとデータサイズを最小限に抑え、できるだけ少ないポインターを使用するようにしてください(余裕のある静的グローバル固定サイズ配列を使用してください)。
ポインタを使用する場合、メモリ内で継続的にジャンプしているため、CPUは毎回キャッシュをリロードする必要があります。 OOPコードはポインタでいっぱいです:すべてのオブジェクトはそのメモリアドレスによって格納されます。オブジェクトをメモリ全体に分散させるためにどこでもnew
を呼び出すと、キャッシュの最適化がほとんど不可能になります(ただし、アロケーターまたはガベージコレクターがあり、物事を互いに近づけます)。コールバックと仮想関数を呼び出します。コンパイラーは通常、仮想関数をインライン化できず、仮想関数の呼び出しは比較的低速です(VMTにジャンプし、仮想関数のアドレスを呼び出します[これには、スタック上のパラメーターとローカル変数をプッシュし、関数を実行してからすべてをポップすることが含まれます])。これは、毎秒0から1000000まで25回実行されるループがある場合に非常に重要です。手続き型スタイルを使用することにより、仮想機能はなく、オプティマイザーはこれらのホットループ内のすべてをインライン化できます。
プロジェクトが小さすぎて1つのクラスに含まれ、あまり長く使用されない場合は、関数の使用を検討します。または、使用している言語がOO(例:c)をサポートしていない場合。
「オブジェクト指向言語の問題は、オブジェクト指向言語が持ち歩く暗黙の環境をすべて備えていることです。バナナが欲しかったのですが、バナナとジャングル全体を保持するゴリラが得られました。」 —ジョーアームストロング
ジャングルが欲しいですか?
2つの概念は相互に排他的ではありません。PPをOOPと組み合わせて使用する可能性が非常に高いため、それらを分離する方法がわかりません。
手続き型プログラムは、特定のタイプのプログラムの方が簡単な場合があります。通常、これらは短いスクリプトのようなプログラムです。
このシナリオを考えてみましょう。コードはOOではありません。プログラム全体にデータ構造と、データ構造を操作する多くの関数があります。各関数はデータ構造をパラメーターとして受け取り、データ構造の「data_type」フィールドに応じて異なる処理を実行します。
すべてが機能していて変更されない場合、それがOOかどうか?それは機能しています。完了しました。手順に従ってより速く書くことができれば、おそらくそれが方法です。トーゴ。
しかし、それが変更されることはないと確信していますか?新しいタイプのデータ構造を追加する可能性が高いとしましょう。これらの関数を操作する新しいデータ構造タイプを追加するたびに、これらの関数をすべて見つけて変更し、必要な動作を確認して追加するための新しい「elseif」ケースを追加する必要があります。新しいタイプのデータ構造に影響を与えます。プログラムが大きく複雑になるにつれて、この問題は大きくなります。これが可能性が高いほど、OOアプローチを使用するほうがよいでしょう。
そして-バグなしで動作していると確信していますか?より複雑なスイッチングロジックは、コードの各ユニットのテストをより複雑にします。ポリモーフィックメソッド呼び出しを使用すると、言語がスイッチングロジックを処理し、各メソッドのテストがより簡単で簡単になります。
OOPの適合性は、プロジェクトのサイズよりも、作業しているサブジェクト領域に依存すると思います。 OOPが関連する概念に自然にマッピングされるいくつかのサブジェクト領域(CAD、シミュレーションモデリングなど)があります。ただし、マッピングが不器用で不調和になるドメインは他にもたくさんあります。すべてにOOPを使用している多くの人は、四角いペグを丸い穴に打ち込むのに多くの時間を費やしているようです。
OOPにはその場所がありますが、手続き型プログラミング、関数型プログラミングなども同様です。解決しようとしている問題を見て、それを解決するための最も簡単なプログラムを作成できるプログラミングパラダイムを選択します。
答えの一部は、使用している言語によって異なります。 Pythonでは、手続き型コードをクラスまたはより正式なオブジェクトに移動するのは非常に簡単です。
私のヒューリスティックの1つは、状況の「状態」がどのようであるかに基づいています。プロシージャが名前空間を汚染する場合、またはグローバル状態に影響を与える可能性がある場合(悪い、または予測できない方法で)、その関数をオブジェクトまたはクラスにカプセル化することはおそらく賢明です。
Grady Boochはかつて、10000行以上のコードでOOP.
しかし、私はいつもOO-wayに行きます。 200行でも。これは長期的には優れたアプローチであり、オーバーヘッドは過大評価された言い訳にすぎません。すべての大きなことは小さなことから始まります。
OOPの目標の1つは、再利用性を容易にすることでしたが、それだけが目的ではありません。オブジェクトを効果的に使用する方法を学ぶための鍵は、デザインパターンです。
私たちは皆、さまざまな手順とデータ構造を組み合わせて一般的なタスクを実行する方法を教えてくれるアルゴリズムのアイデアに慣れています。逆に、オブジェクトを組み合わせて一般的なタスクを実行する方法については、Gang ofFourによるデザインパターンを参照してください。
デザインパターンについて学ぶ前は、スーパータイプの構造として以外にオブジェクトを効果的に使用する方法についてはほとんど暗闇でした。
インターフェイスの実装は、継承よりも重要ではないにしても、同じくらい重要であることを忘れないでください。当時、C++はオブジェクト指向プログラミングの主要な例であり、インターフェイスの使用は継承(仮想関数など)と比較してあいまいです。 C++ Legacyは、さまざまなチュートリアルと幅広い概要で動作を再利用することに重点が置かれていることを意味します。それ以来、Java、C#、およびその他の言語は、インターフェースをより焦点に移しました。
インターフェイスが優れているのは、2つのオブジェクトがそれぞれとどのように相互作用するかを正確に定義することです。行動を再利用することではありません。結局のところ、私たちのソフトウェアの多くは、さまざまな部分がどのように相互作用するかに関するものです。したがって、インターフェイスを使用すると、再利用可能なコンポーネントを作成するよりもはるかに生産性が向上します。
他の多くのプログラミングのアイデアと同様に、オブジェクトはツールであることを忘れないでください。あなたはそれらがあなたのプロジェクトのためにどれだけうまくいくかに関してあなたの最善の判断を使わなければならないでしょう。金属切削機用の私のCAD/CAMソフトウェアには、オブジェクトに配置される理由がないため、オブジェクトに配置されない重要な数学関数があります。代わりに、それらはライブラリから公開され、それらを必要とするオブジェクトによって使用されます。次に、それらの構造が自然にこのセットアップにつながるため、オブジェクト指向にされたいくつかの数学関数があります。 (ポイントのリストを取得し、それをいくつかの異なるタイプのカッティングパスに変換します)。もう一度あなたの最善の判断を使用してください。
私の2セント...
手続き型プログラミングの利点
手続き型コードが優れているほど、関数型に近づきます。そして、FPの利点はよく知られています。
プログラミング中に「OOを考える」場合、「いつ手続き型プログラミングに戻すべきか」と尋ねるのが理にかなっているのかわかりません。これは、Javaにクラスが必要なため、Javaプログラマーに何ができないかを尋ねるのと同じです。 (同上.NET言語)。
手続き的に考えを乗り越える努力をしなければならない場合は、それを克服する方法について質問することをお勧めします(気になる場合)。それ以外の場合は、手続き型のままにします。 OOPモードに入るのにそれほどの努力が必要な場合は、OOPコードはおそらくうまく機能しません(学習曲線に沿って進むまで)。
私は常にトップダウン方式で設計を開始し、上部ではOOPの用語で考える方がはるかに簡単です。しかし、特定の部分をコーディングするときが来ると、生産性が大幅に向上します。手続き型プログラミングだけです。OOPは、プロジェクトの設計と形成に優れているため、divide-et-imperaパラダイムを適用できます。ただし、コードのすべての側面に適用できるわけではありません。それは宗教でした:)
あなたは両方の概念で悪いソフトウェアを書くことができます。それでも、複雑なソフトウェアは、手続き型言語よりもOO言語)で記述、理解、保守するのがはるかに簡単です。非常に複雑なERPアプリケーションを手続き型言語(Oracle PL/SQL)、次にOOP(C#)に切り替えました。これまでも今も新鮮な空気の息吹です。
ほとんどの研究では、OOコードは手続き型コードよりも簡潔であることがわかっています。既存のCコードをC++で書き直したプロジェクトを見ると(私が必ずしもアドバイスするものではありませんが)、通常は次のようになります。コードサイズを50〜75パーセント削減します。
したがって、答えは-常にOOを使用してください!
IMHO、OOPの長期的なメリットは、短期的に節約された時間よりも重要です。
AZが言ったように、OOPを手続き的に使用すること(私はかなり行います)は、(小さなプロジェクトの場合)良い方法です。プロジェクトが大きいほど、OOP採用する必要があります。