2016-04-29 13 views
3

公正な警告 - ずっと前に私はC++をたくさん書いていましたが、私が以前知っていたデザインパターンにjavascriptを強制する誘惑を助けることはできません。これは、工場出荷時のパターンを示して私の現在のプロジェクト、私は名前でオブジェクトを作成したい、ではどの回答;-)これは新しいjavascriptの工場パターンですか?


に先祖帰りの私を非難しても大丈夫です。だから私はGoogleのヒットのトップページを 'javascript factory pattern'のために読んだ。 2つの問題がある

if (name === 'FactoryPartA') { 
    parentClass = PartA; 
} else if (name === 'FactoryPartB') { 
    parentClass = PartB; 
} else if ... 
    parentClass = PartZ; 
} 

return new parentClass(); 

:彼らはすべて共通で、この醜い事持って

  1. 私が作る工場のために新しいパーツを作成するたびに、私は「工場の実装を編集することがあると私d両方の作業を避けることを好む。&バグ挿入の機会。
  2. これはハードコーディングされた線形検索で、「効率性」をほとんど叫ばないものです。工場の閉鎖register内の工場の部品のクラスを定義するの戦術が提供するモジュールパターンのメリットを隠す情報を持つモジュールと工場パターンの組み合わせ -

は、だからここに私が思い付いたものです。

最終的に私の質問に:私はこれまでに私よりも優れたコーダーによって行われたとは思えませんので、もしあなたが知っていれば工場のパターンでこのツイストの標準バージョンへのリンクを共有してください。

N.B.この例では、すべてのコードを一緒に実行しています。私のプロジェクトでは、Factory、FactoryPartA、FactoryPartB、およびクライアントコードはすべて別々のファイルにあります。

namespace('mynamespace'); 

// object factory 
mynamespace.factory = (function() { 
    'use strict'; 
    var api = {}; 
    var registry = []; 

    // register an item 
    api.register = function (item) { 
     if (registry.some (function (r) {return r.name === item.name;})) { 
      throw new Error ('factory.register(): name collision detected: ' + name); 
     } else { 
      registry.push(item); 
     } 
    }; 

    // make an item given its name 
    api.make = function (name) { 
     var item = null; 
     var idx = registry.findIndex (function (r) { 
      return r.name === name; 
     }); 
     if (idx >= 0) { 
      item = new registry[idx].make(); 
     } 
     return item; 
    }; 

    return api; 

})(); 


// define a module & register it with factory 
mynamespace.factory.register ({ 
    name: 'FactoryPartA', 
    make: function FactoryPartA() { 
     'use strict'; 
     var label = 'Factory Part A'; // private property 

     this.test = undefined; // public property 

     this.label = function() { // public method 
      return label; 
     }; 

     return this; 
    } 
}); 

// define a different module & register it with factory 
mynamespace.factory.register ({ 
    name: 'FactoryPartB', 
    make: function FactoryPartB() { 
     'use strict'; 
     var label = 'Factory Part B'; 

     this.test = undefined; 

     this.label = function() { 
      return label; 
     }; 

     return this; 
    } 
}); 

// client code 
var aPart = mynamespace.factory.make('FactoryPartA'); 
var bPart = mynamespace.factory.make('FactoryPartB'); 

console.log (aPart.label()); // logs 'Factory Part A' 
console.log (bPart.label()); // logs 'Factory Part B' 

var anotherPart = mynamespace.factory.make('FactoryPartA'); 
aPart.test = 'this one is not'; 
anotherPart.test = 'the same as this one'; 
console.log (aPart.test !== anotherPart.test); // logs true 
+4

ダイナミック工場のリンクのこの種のは、まさに問題の依存性の注入は、([自分のライブラリへの恥知らずのリンク](https://github.com/ssube/noicejs))を解決するために作成しました。 – ssube

答えて

4

基本的な質問に答えるには、これは新しいJavascriptの工場パターンですか?いいえ、そうではありません。 (ES6/ES2015,Typescript、Aureliaの依存関係注入モジュールをチェックしてください)

ここでは、本質的に何をしているのか、Javascriptの「クラス」タイプにメタデータを追加しようとしています。つまり、あなたが工場の工場を作りようとしているように見えます。あなたが必要とするかどうかはわかりません。 (おそらく、あなたはあなたの例を簡略化してきました。)

あなたの例では、私はより多くのこのような何かだろう:それはFactoryFactoryないように、これは余分な工場のものを削除し

namespace('mynamespace'); 

// object factory 
mynamespace.factory = (function() { 
    'use strict'; 
    var api = {}; 
    var registry = {}; 

    // register an item 
    api.register = function (name, item, overwrite) { 
     if (!overwrite || registry.hasOwnProperty('name')) { 
      throw new Error ('factory.register(): name collision detected: ' + name); 
     } 

     registry[name] = item; 
    }; 

    // make an item given its name 
    api.make = function (name) { 
     var item = registry[name]; 
     return item ? new item() : null; // or better, Object.create(item); 
    }; 

    return api; 

})(); 


// define a module & register it with factory 
mynamespace.factory.register ('FactoryPartA', function FactoryPartA() { 
    'use strict'; 
    var label = 'Factory Part A'; // private property 

    this.test = undefined; // public property 

    this.label = function() { // public method 
     return label; 
    }; 
}); 

// define a different module & register it with factory 
mynamespace.factory.register ('FactoryPartB', function FactoryPartB() { 
    'use strict'; 
    var label = 'Factory Part B'; 

    this.test = undefined; 

    this.label = function() { 
     return label; 
    }; 
}); 

を。さらに、線形検索について言及しました。配列の代わりにオブジェクトを使うと、リニアルックアップ(オブジェクトのハッシュは定時検索です)を避けることができます。最後に、実際にラッパーオブジェクトに配置することなく任意の名前を登録することができます。これはDIに近い。

あなたは本当にメタデータスタイルのアプローチを行いたい場合は、しかし、あなたは次のような何かを行うことができます:

namespace('mynamespace'); 

// object factory 
mynamespace.factory = (function() { 
    'use strict'; 
    var api = {}; 
    var registry = {}; 

    // register an item 
    api.register = function (item, overwrite) { 
     if (!overwrite || registry.hasOwnProperty(item.name)) { 
      throw new Error ('factory.register(): name collision detected: ' + item.name); 
     } 

     registry[item.name] = item; 
    }; 

    // make an item given its name 
    api.make = function (name) { 
     var item = registry[name]; 
     return item ? new item() : null; // or better, Object.create(item); 
    }; 

    return api; 

})(); 


// define a module & register it with factory 
mynamespace.factory.register (function FactoryPartA() { 
    'use strict'; 
    var label = 'Factory Part A'; // private property 

    this.test = undefined; // public property 

    this.label = function() { // public method 
     return label; 
    }; 
}); 

// define a different module & register it with factory 
mynamespace.factory.register (function FactoryPartB() { 
    'use strict'; 
    var label = 'Factory Part B'; 

    this.test = undefined; 

    this.label = function() { 
     return label; 
    }; 
}); 

これは、代わりに別のプロパティの関数名を使用しています。 (関数は、Javascriptでは名前を付けることができますが、このメソッドは匿名関数では機能しません)上記のTypescriptは、TypescriptがJavascriptにコンパイルされたとき、実際には、 。Aureliaの依存関係注入については、@autoinjectの機能が実際にこのメタデータを読み込んでオブジェクトを作成していることに似ています。

しかし、あなたは依存性注入コンテナを作成しようとしている場合を除き、本当に....(あなたの例であるよりも多くのロジックを必要とする - あなたは同様のインスタンスを指すことができますキーを持つコンテナをしたいと思います)Iあなたはこのパターンでよりも多くの機能をObject.create()Object.assign()から得ると主張します。静的に型付けされた強く型付けされコンパイルされた言語で必要とする多くのデザインパターンは、その環境外では必要ありません。あなたはこれを行うことができます:

function PartA() { 
    'use strict'; 
    var label = 'Factory Part A'; // private property 

    this.test = undefined; // public property 

    this.label = function() { // public method 
     return label; 
} 

function PartB() { 
    'use strict'; 
    var label = 'Factory Part B'; 

    this.test = undefined; 

    this.label = function() { 
     return label; 
    }; 
} 

var A = Object.create(PartA); 
var B = Object.create(PartB); 

これは、はるかに簡単です。

+0

このような包括的で明るい答えに感謝します。ハッシュが一定時間であることがわかっているのは本当に便利です。 – VorpalSword

+0

残りは役に立つと思います。これは必ずしも最善の答えではありません。私は質問と答えに関連する多くの詳細をスキム(スキップ)しました。我々が使用するデザインパターンのほとんどは、タイプシステムを私たちの望みに強要するように調整されています。また、主に古典的なOOP用に設計されています。さらに、これらのデザインパターンのいくつかは、高級言語では不要です。 JavaScriptに関するドキュメントを読むことを強くお勧めします。高度な機能を使用して機能し、機能面を使って定型表現を避けることができます。 –

関連する問題