2017-01-31 15 views
0

私は以下のクラス 'Grid'をArrayから拡張していますが、双方向配列のメソッドを実装する目的で、現在はコンストラクタ関数はありません。簡潔にするために、私は不快な機能を示しています:Grid.getPlaneは、パラメータで構築されたサブグリッドを返します。ES6で呼び出すインスタンスと同じクラスのオブジェクトを生成

class Grid extends Array { 
//... 
    getPlane(width, height, x, y) { 
    let myPlane = new Grid; 
    // calculations... 
    return myPlane; 
    } 
//... 
} 

私は、この1つから延びる別のクラス 'テレイン'を持っています。これは、地形データのためのより特定の機能性を有することを意図したものである。意図した機能は、私が 'Terrain'クラスのインスタンスの 'getPlane'関数を呼び出すたびに返されるオブジェクトも 'Terrain'クラスであることです(このクラスに固有の関数を使用することができます)。あなたは私のどちらかが醜い重複コードで私を残し、「グリッド」から継承された関数の宣言を使用し、(代わりに、地形の)グリッドを取得、または関数を上書き予測することができますようしかし:

class Terrain extends Grid { 
//... 
    getPlane(width, height, x, y) { 
    let myPlane = new Terrain; 
    // calculations... 
    return myPlane; 
    } 
//... 
} 

私が使用しようとしましたObject.create in:

let myPlane = Object.create(this.prototype) 

戻り値は未定義です。 そして

let myPlane = Object.create(this.constructor.prototype) 

は私のアレイのように動作していない「地形」という名前のオブジェクトを提供します。 Object.createが 'this'オブジェクトと同じクラスのオブジェクトを取得する方法はありますか?または任意の他の同じクラスでオブジェクトを生成する方法?

答えて

1

これはの場合です:保守性システムを書くの痛みを伴う方法であることsuper

  • 深くネストされた階層の方法に呼び出すの欠如
  • あまりにも多くを行う

    1. 方法。

    まずJSに4000倍を乗じた:

    // assume 
    class A extends Array { 
        doX (x) { 
        console.log(`A.doX(${x})`); 
        return new A(); 
        } 
    } 
    
    class B extends A { 
        doX (x, y) { 
        super.doX(x); 
        console.log(`B.doX(${x}, ${y})`); 
        return new B(); 
        } 
    } 
    
    class C extends B { 
        doX (x, y, z) { 
        super.doX(x, y); 
        console.log(`C.doX(${x}, ${y}, ${z})`); 
        return new C(); 
        } 
    } 
    
    
    const c = new C(); 
    c.doX(1, 2, 3); 
    // "A.doX(1)" 
    // "B.doX(1, 2)" 
    // "C.doX(1, 2, 3)" 
    

    を今、私はこのコードを実行している全く問題がないことを期待すべきです。
    しかし、私は実際にそれを利用しています。

    なぜですか?私は同時に構造とロジックを心配する方法に過負荷をかけることにしました。

    Aクラスは常にAを返します。スーパークラスは実際には全く異なるオブジェクト(新しいA)を返しますが、Bクラスは常にBを返します。 CはすでにAとBを作成していますが、Aへの参照はありませんが、Cは新しいCを返します。

    あなたは何をしていますか?

    思考のカップル:

      はあなたのライブラリーからデータオブジェクトを分離代わり
    • 、対象外道いったいオブジェクトの構築を移動し、それを渡す

    それでは、建設分離

    を試してみましょう
    class Person { 
        static make() { return new Person(); } 
        setDetails (name, age) { 
        this.name = name; 
        this.age = age; 
        } 
        clone (cfg = this) { 
        const person = Person.make(); 
        person.setDetails(cfg.name, cfg.age); 
        return person; 
        } 
    } 
    
    class Employee extends Person { 
        static make() { return new Employee(); } 
        setDetails (name, age, id) { 
        super.setDetails(name, age); 
        this.id = id; 
        } 
        clone (cfg = this) { 
        const employee = Employee.make(); 
        employee.setDetails(cfg.name, cfg.age, cfg.id); 
        return employee; 
        } 
    } 
    

    cloneメソッドは継承されません。彼らはインスタンス化に焦点を当てています。それらは基本的にファクトリです(実際には別のオブジェクトの領域、またはmake|from|of|empty|unitのような静的メソッドです)。

    次に、インスタンスメソッドであるコンストラクタを実行する必要があるか、工場で何を行うべきかを呼び出すsetDetailsを呼び出しています。に継承されています。

    DRYと言いますと、継承はそのようにとどまる恐ろしい方法です。私が書いたことから、コンストラクタのオーバーライド(clonemake)、または親への呼び出し(super)、あるいは単に拡張について心配している行がいくつあったのでしょうか?

    これは、ライブラリ、純粋な関数/メソッド、装飾という異なるパターンに私をもたらします。

    実際の「タイプ」(および生のJSではコンソールで役に立ちますが、他の場所では役に立たないので気にしない場合)は、データ中心のオブジェクトを楽しく作成できます。
    構造体はC、Go、Pythonなどと同じように表示されます。

    これらの構造体(または理想的にはそのコピー)で使用するライブラリ/サービスに必要な再利用可能な計算をすべて記述することができます。あなたはあなたのコードは、その時点でDRYされていない文句苦労しなければならないと思い

    class Vector { 
        add2D (
        {x: x1, y: y1}, 
        {x: x2, y: y2} 
    ) { 
        return Vector2D.of(x1 + x2, y1 + y2); 
        } 
    } 
    
    class Vector2D { 
        constructor (x, y) { 
        return Object.assign(this, { x, y }); 
        } 
        static of (x, y) { return new Vector2D(x, y); } 
        static from ({ x, y }) { return Vector2D.of(x, y); } 
        static empty() { return Vector2D.of(0, 0); } 
    } 
    
    const vector = vectors 
        .map(Vector2D.from) 
        .reduce(Vector.add2D, Vector2D.empty()); 
    
    // Vector2D { x: 42, y: 21 } 
    

    class Vector { 
        static make2D (x = 0, y = 0) { 
        return { x, y }; 
        } 
        static make3D (x = 0, y = 0, z = 0) { 
        return { ...Vector.make2D(x, y), z }; 
        } 
        static add2D (v1, v2) { 
        return Vector.make2D(v1.x + v2.x, v1.y + v2.y); 
        } 
    } 
    
    
    const vectors = [ 
        { x: 0, y: 1 }, 
        { x: 32, y: 8 }, 
        { x: 10, y: 12 }, 
        { x: 0, y: 0 }, 
    ]; 
    
    const vectorSum = vectors.reduce(Vector.add2D, Vector.make2D()); 
    vectorSum; // { x: 42, y: 21 } 
    

    あなたが実際にそれらを必要に応じて

    は、あなたのような何かを行うことができ、型付けされます。入力データに5Dベクトルを入れても、正しい2Dベクトルが出力されます。

  • 関連する問題