web-dev-qa-db-ja.com

javascriptでポリモーフィズムを使用する必要がありますか?

私は、機能的でOO指向)の両方のいくつかの言語でプログラミングしたプログラマーです。Javascriptもプログラミングしましたが、ポリモーフィズムを使用したことはありません(または使用する必要がありました)。

さて、一種の趣味のプロジェクトとして、Javaとポリモーフィズムを多用するC#で書かれたいくつかのアプリをJavascriptに移植したいと思います。

しかし、一見したところ、私はたくさんの「それは可能ですが...」を読みました。

それで、それに代わるものはありますか?

私がJSでpseudolangで書きたいものの例:

abstract class Shape{ { printSurface() } ;  }

class Rect : Shape() {  printSurface() { print (sideA*sideB}}

class Circle : Shape() {  printSurface() { print { pi*r*r }}

TheApp { myshapes.iterate(shape s) {s.printSurface() } }

つまり、古典的な多型の場合:ベースクラスを反復処理します。

このような振る舞いを実現したいと思います。私はそれを知っていますisポリモーフィズムですが、この種の動作を実現するために私が見落としている他の「パターン」はありますか、それともJavascriptで継承の可能性を研究する必要がありますか?

32
Peter

前述のように、JavaScriptはプロトタイプの継承に基づく動的な型付き言語であるため、型付き言語と同じアプローチを実際に使用することはできません。あなたが書いたもののJSバージョンは次のようになります。

function Shape(){
  throw new Error("Abstract class")
}

Shape.prototype.printSurface = function () {
  throw new Error ("Not implemented");
}

function Rect() {
  // constructor;
}

Rect.prototype = Object.create(Shape.prototype);
Rect.prototype.printSurface = function() {
  // Rect implementation
}

function Circle() {
  // constructor;
}

Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.printSurface = function() {
  // Circle implementation
}

次に、アプリで:

var obj = new Circle();

if (obj instanceof Shape) {
    // do something with a shape object
}

または、ダックタイピングの場合:

if ("printSurface" in obj)
    obj.printSurface();

// or

if (obj.printSurface)
    obj.printSurface();

// or a more specific check
if (typeof obj.printSurface === "function")
    obj.printSurface();

また、コンストラクターのないオブジェクトとしてShapeがあり、次のような「抽象クラス」になっています。

var Shape = {
    printSurface : function () {
        throw new Error ("Not implemented");
    }
}

function Rect() {
  // constructor;
}

Rect.prototype = Object.create(Shape);
Rect.prototype.printSurface = function() {
  // Rect implementation
}

function Circle() {
  // constructor;
}

Circle.prototype = Object.create(Shape);
Circle.prototype.printSurface = function() {
  // Circle implementation
}

この場合、instanceofを使用できなくなったため、ダックタイピングにフォールバックするか、isPrototypeOfを使用する必要がありますが、最近のブラウザでのみ使用できます。

if (Shape.isPrototypeOf(obj)) {
    // do something with obj
}

Object.create ES5仕様を実装していないブラウザーでは使用できませんが、ポリフィルを簡単に使用できます(リンクを参照)。

43
ZER0

ここでの「パターン」は「インターフェース」です。 myshapesコレクション内のすべてのオブジェクトがprintSurface()メソッドを実装している限り、問題はありません。

Javascriptは動的に型指定された言語であるため、コレクション内のオブジェクトを関連付ける必要はまったくありません。

13
Weston

私はこれがプロトタイプでできることを知っていますが、私はそれを使うことの達人ではありません。 私はオブジェクトリテラルアプローチを好みます (視覚化が容易で、「プライベート」スコープがあります)

//shape class
var shape = function() {
    //return an object which "shape" represents
    return {
        printSurface: function() {
            alert('blank');
        },
        toInherit: function() {
            alert('inherited from shape');
        }
    }
};

//rect class
var rect = function() {
    //inherit shape
    var rectObj = shape();

    //private variable
    var imPrivate = 'Arrr, i have been found by getter!';

    //override shape's function
    rectObj.printSurface = function(msg) {
        alert('surface of rect is ' + msg);
    }

    //you can add functions too
    rectObj.newfunction = function() {
        alert('i was added in rect');
    }

    //getters and setters for private stuff work too
    rectObj.newGetter = function(){
        return imPrivate;
    }

    //return the object which represents your rectangle
    return rectObj;
}



//new rectangle
var myrect = rect();

//this is the overridden function
myrect.printSurface('foo');

//the appended function
myrect.newfunction();

//inherited function
myrect.toInherit();

//testing the getter
alert(myrect.newGetter());

7
Joseph

Westonが言うように、継承の必要がない場合は、Javascriptなどの動的言語のダックタイピングの性質により、言語自体に強く型付けされた基本クラスまたはインターフェイスの要件がないため、ポリモーフィズムが得られます。

継承を使用して、スーパークラスの実装を簡単に呼び出すなどの操作を行う場合は、Joesephが示すように、プロトタイプまたはオブジェクトリテラルを使用してこれを実現できます。

もう1つは、 Coffescript を確認することです。これはJavascriptにコンパイルされるため、すべてのOOの良さを単純な構文で提供します。これにより、すべてのbollerplateプロトタイピングが記述されます。欠点は、この余分なコンパイル手順が追加されることです。つまり、上記の例のような単純なクラス階層を作成し、その結果としてJavaScriptがどのように表示されるかを確認すると、すべてを実行する方法を示すのに役立ちます。

4
Johnno Loggie

別の注意点。クラスを使用してJavascriptをOOスタイルでプログラムする場合は、Javascriptの多くの「クラスシステム」を調べることができます。1つの例はJoose(http://joose.it)です。

多くのクライアント側フレームワークは、独自のクラスシステムを実装しています。この例はExtJSです。

4
Weston