2016-12-08 62 views
1

的我有一個類,我想要一個簡單的工廠方法:強制使用工廠

class GTree{ 

    public static createNode(){ 
     return new GNode(); 
    } 

} 

這意味着,我不想讓消費者立即實例化的GNode。

我該如何正確實施?

很顯然,我不能這樣做:

class GNode{ 
    constructor(){ 
     throw TypeError("This is nonsense"); 
    } 
} 

因爲那時我不能再在所有創建節點。
我該如何強制使用工廠?

+0

你需要防範什麼?或者你只是想設置一種編碼風格? – Bergi

+0

@Bergi我不希望消費者實例化與樹實例無關的節點。 – Trace

+0

「無關」是什麼意思?你可以分享代碼嗎? – Bergi

回答

2

這是比我以前的評論更簡單的方案。就在一個私人的(但共享)範圍定義GNode類,因此這是唯一的地方構造可以被調用,也重置.constructor屬性,因此它不會泄露:

const GTree = (function() { 
 
    class GNode { 
 
     constructor() { 
 

 
     } 
 

 
     someOtherMethod() { 
 
      console.log("someOtherMethod"); 
 
     } 
 
    } 
 
    // reset public .constructor 
 
    GNode.prototype.constructor = function() { 
 
     throw new Error("Can't call GNode constructor directly"); 
 
    }; 
 

 
    class GTree { 
 
     constructor() { 
 
      this.nodes = []; 
 
     } 
 

 
     createNode() { 
 
      let node = new GNode(); 
 
      this.nodes.push(node); 
 
      return node; 
 
     } 
 

 
     get length() { 
 
      return this.nodes.length; 
 
     } 
 
    } 
 
    return GTree; 
 
})(); 
 

 

 
let tree = new GTree(); 
 
let node1 = tree.createNode(); 
 
let node2 = tree.createNode(); 
 
node1.someOtherMethod(); 
 
console.log(tree.length + " nodes");

+0

對不起,但[這是錯誤的](http://stackoverflow.com/q/38739499/1048572)。每次調用方法時都會創建一個新類;我不認爲我必須解釋爲什麼這是不好的。並且'let node3 = new(node2.constructor)()'是微不足道的...... – Bergi

+1

@Bergi - 你是對的。我已經在最新版本中解決了這兩個問題。 – jfriend00

+0

@KimGysen - 我想出了一個更簡單/更乾淨的方式來做到這一點。 – jfriend00

2

你不能真正做到這一點在JavaScript,但你可以這樣做:

export class GTree { 
    public static createNode(name: string): GNode { 
     return new GNodeImpl(name); 
    } 
} 

export interface GNode { 
    name: string; 
} 

class GNodeImpl implements GNode { 
    constructor(public name: string) {} 
} 

code in playground

只有GTreeGNode接口出口,這意味着它是不可能的實例來自模塊外部的GNodeImpl

我爲示例添加了name屬性。

+0

這回答我的問題,謝謝。對於我的實際實施,我會考慮給出的意見,然後做出決定。 – Trace