web-dev-qa-db-ja.com

プロトタイプベースのOOPクラスベースのOOPより優れている点は何ですか?

クラスベースの言語のコンテキストでOOPを主に扱った後、初めてJavascriptのプログラミングを始めたとき、プロトタイプベースのOOPがこれまでにクラスベースのOOPよりも優先されます。

  1. プロトタイプベースのOOPを使用することの構造上の利点は何ですか? (たとえば、特定のアプリケーションでは、メモリの消費が高速になるか、メモリ使用量が少なくなると思いますか?)
  2. コーダーの観点からの利点は何ですか? (たとえば、プロトタイピングを使用すると、特定のアプリケーションをコーディングしたり、他の人のコードを拡張したりする方が簡単ですか?)

この質問を、特にJavascriptに関する質問と見なさないでください(長年にわたって、プロトタイピングとはまったく関係のない多くの障害がありました)。代わりに、プロトタイピングとクラスの理論的な利点を組み合わせて見てください。

ありがとうございました。

48
Deets McGeets

JavaでRPGゲームを書くとき、私は両方のアプローチについてかなりの経験をしました。もともと私はクラスベースのOOPを使用してゲーム全体を記述しましたが、最終的にこれが間違ったアプローチであることに気付きました(クラス階層が拡大するにつれて、それは維持できなくなりました)。したがって、コードベース全体をプロトタイプベースのコードに変換しました。その結果、管理がmuchよくなり、簡単になりました。

興味があればここにソースコード( 暴君-Java Roguelike

主な利点は次のとおりです。

  • 新しい「クラス」を作成するのは簡単です-プロトタイプをコピーして、いくつかのプロパティを変更して、新しいクラスを作成します。これを使用して、たとえば、Javaの3〜6行で、新しいタイプのポーションを定義しました。新しいクラスファイルやボイラープレートのロードよりもはるかに優れています。
  • 比較的少ないコードで非常に大量の「クラス」を構築および維持することが可能です-たとえば、暴君は約42,000行しかない3000の異なるプロトタイプのようなものを持っていましたコード合計の。これはJavaにとってかなりすばらしいことです。
  • 多重継承は簡単です-あるプロトタイプからプロパティのサブセットをコピーし、別のプロトタイプのプロパティに貼り付けるだけです。たとえばRPGでは、「スチールゴーレム」に「スチールオブジェクト」の一部のプロパティ、「ゴーレム」の一部のプロパティ、および「インテリジェントモンスター」の一部のプロパティを持たせることができます。プロトタイプで簡単に、継承階層でそれをやってみてください......
  • プロパティ修飾子で賢いことができます-一般的な「プロパティの読み取り」メソッドに巧妙なロジックを配置することで、さまざまな修飾子を実装できます。たとえば、魔法の指輪を定義するのは簡単で、身に着けている人に+2の強さを加えました。このロジックはリングオブジェクト内にあり、「読み取り強度」メソッドではではないので、コードベースの他の場所(たとえば、「is強さの輪をつけたキャラクターが増える?
  • インスタンスは他のインスタンスのテンプレートになることができます-たとえば、オブジェクトを「クローン」するのは簡単で、既存のオブジェクトを新しいオブジェクトのプロトタイプとして使用するだけです。異なるクラスの複雑なクローニングロジックをたくさん書く必要はありません。
  • 実行時に動作を変更するのは非常に簡単です-つまり、実行時にプロパティを変更し、オブジェクトをほぼ任意に「モーフ」できます。クールなゲーム内効果を可能にします。これを「スクリプト言語」と組み合わせると、実行時にほとんど何でも可能になります。
  • これは、プログラミングの「関数型」スタイルに適しています-組み込みロジックではなく、オブジェクトの動作を適切に分析する多くの関数を作成する傾向があります特定のクラスに関連付けられたメソッド内。私は個人的にこれを好みますFPスタイル。

主な欠点は次のとおりです。

  • 静的型付けの保証を失います-動的オブジェクトシステムを効果的に作成しているためです。これは、動作が正しいことを確認するために、より多くのテストを作成する必要があり、オブジェクトが適切な「種類」であることを意味する傾向があります
  • パフォーマンスオーバーヘッドが発生します-オブジェクトプロパティの読み取りは通常、1回以上のマップルックアップを実行する必要があるため、パフォーマンスの点でわずかなコストがかかります。私の場合は問題ではありませんでしたが、場合によっては問題になる可能性があります(たとえば、すべてのフレームで多数のオブジェクトが照会される3D FPS)
  • リファクタリングは同じように機能しません-プロトタイプベースのシステムでは、本質的にコードで継承階層を「構築」しています。 IDE /リファクタリングツールは、アプローチを理解できないため、実際には役立ちません。私はこれが問題であるとは決して知りませんでしたが、注意しないと手に負えなくなる可能性があります。おそらく、継承階層が正しく構築されていることをテストで確認する必要があります。
  • これは少しエイリアンです-従来のOOP=スタイルに慣れている人は簡単に混乱するかもしれません。「どういう意味ですか? "Thing"と呼ばれるクラスは1つだけ?!? "-"この最後のThingクラスを拡張するにはどうすればよいですか!?! "-"違反していますOOP原則!!! "-"それは間違っていますあらゆる種類のオブジェクトに作用するこれらすべての静的関数がある!?!?」

最後にいくつかの実装ノート:

  • 私はJava HashMapとプロトタイプの「親」ポインタを使用しました。これはうまく機能しましたが、次の欠点がありました:a)プロパティの読み取りは、長い親チェーンをたどってトレースする必要がありました。パフォーマンスの低下b)親プロトタイプを変更した場合、変更は、変更中のプロパティをオーバーライドしていないすべての子に影響します。注意しないと、微妙なバグが発生する可能性があります。
  • 私がこれをもう一度行っていた場合、プロパティに不変の永続マップを使用します(一種の Clojureの永続マップ )、 または私自身のJava永続的なハッシュマップの実装 。次に、不変の動作と相まって安価なコピー/変更の利点が得られ、オブジェクトを親に永続的にリンクする必要がなくなります。
  • オブジェクトのプロパティに関数/メソッドを埋め込むと、楽しいことがあります。私がJava for this( "Script" classの匿名サブタイプ)で使用したハックはあまりエレガントではありませんでした。これをもう一度行うと、おそらく適切な埋め込み容易な言語を使用するでしょう。スクリプト(ClojureまたはGroovy)
47
mikera

プロトタイプベースの主な利点OOPそのオブジェクトと「クラス」は実行時に拡張できます。

クラスベースのOOPにはいくつかの優れた機能がありますが、残念ながら、それはプログラミング言語に依存します。

Object Pascal(Delphi)、VB.NetおよびC#には、プロパティ(フィールドと混同しないでください)およびプロパティのアクセスメソッドを使用する非常に直接的な方法がありますが、Java&C++、プロパティにアクセスしますまた、PHPには、「マジックメソッド」と呼ばれる両方が混在しています。

いくつかの動的型付けクラスがありますが、メインクラスO.O.言語には静的型付けがあります。クラスO.O.での静的型付けそれらのI.D.E.を作成できるオブジェクトイントロスペクションと呼ばれる機能を許可するため、非常に便利です。 Webページを視覚的かつ迅速に開発します。

2
umlcat

@umlcatに同意する必要があります。クラス拡張は大きな利点です。たとえば、長期間にわたって文字列クラスに機能を追加したいとします。 C++では、以前の文字列クラスの世代を継承し続けることによってこれを行います。このアプローチの問題は、各世代が本質的に独自の異なるタイプになり、既存のコードベースの大量の書き換えにつながる可能性があることです。プロトタイプの継承を使用すると、新しいメソッドを元の基本クラスに「アタッチ」するだけで、どこにでも継承クラスと継承関係を大規模に構築する必要がありません。私は、C++が新しい標準で同様の拡張メカニズムを考え出すことを望んでいます。しかし、彼らの委員会は、キャッチーで人気のある機能を追加したい人々によって運営されているようです。

0
annoying_squid