2012-10-30 22 views
12

我在Node.js中編寫了一些代碼,這些代碼跳出了我,因爲它使用策略模式更好地進行了結構化。來自.Net我會創建其他基於並從那裏移動的界面,在JavaScript中,這不是很清楚。正在嘗試模仿JavaScript中的一個接口/抽象類不良練習

我理解爲一種典型的語言JavaScript沒有接口繼承的概念,所以我不確定我所做的是否是一種氣味,因爲我似乎找不到引用,除了一篇博客文章嘗試通過使用強制繼承類實現函數的基本抽象類來推斷接口(當它拋出時)。

我的基類

QueryStrategy = function() { 

}; 

QueryStrategy.prototype.create = function(){ 
throw new Error("Not Implemented"); 
} 

module.exports = QueryStrategy; 

實施1

var util = require('util'); 
var QueryStrategy = require('./queryStrategy'); 

SelectQueryStrategy = function (query) { 
    this.parameters = query.parameters || []; 
    this.entity = query.entity || ''; 
}; 

util.inherits(SelectQueryStrategy, QueryStrategy); 

SelectQueryStrategy.prototype.create = function() { 
    var self = this, 
     params = self.parameters, 
     paramList = self.parameters.length >= 1 ? '' : '*'; 

    for (var i = 0; i < params.length; i++) { 
     var suffix = i === (params.length - 1) ? '' : ', '; 
     paramList = paramList + params[i].key + suffix; 
    } 

    return util.format("SELECT %s FROM %s", paramList, self.entity); 
}; 

module.exports = SelectQueryStrategy; 

目前鹼不具有任何共享功能或性質。共享函數會來,屬性,因爲原型鏈搜索我沒有看到添加「共享」屬性的重點,因爲它們被創建的實例覆蓋(請如果這是錯誤的,讓我知道)。

這是一個可接受的方法,或者我應該忽視在這種情況下的繼承。可能有一些類型檢查,如果你可以推斷類型爲1(即它們都必須是Type QueryStrategy類型),但它不會讓我的.Net偏見接管這裏。

另類視角

首先,我並不想在這裏賣書,我正在看周圍的主題有很多的書籍,我有,但希望給予信貸,其應有的。

基於這幾條評論,說這種類型推斷在這裏沒有任何區別,可能應該只是留給Duck Typing來檢查,也許試圖插入一些東西是正確的沒有在語言中定義並不是最好的方法。我已經閱讀過關於接口的Addy Osmani Javascript模式,儘管我的實現不盡相同,儘管接口的使用是可以接受的,但它可能不是必需的。

保持策略方法可能會更簡單,但使用不同的實現方式,Stoyan Stefanov在Javascript Patterns中概述了一種方法,其中有一種實現方式,並且基於某種形式的配置,您知道使用哪種策略。

僞樣本

QueryBuilder = function() { 
    this.types = []; 
} 

QueryBuilder.prototype.create = function (type, query) { 
    var strategy = types[type]; 
    strategy.create(query); 
}; 

QueryBuilder.types.Select = { 

    create: function (query) { 
     params = query.parameters, 
     paramList = query.parameters.length >= 1 ? '' : '*'; 

     for (var i = 0; i < params.length; i++) { 
      var suffix = i === (params.length - 1) ? '' : ', '; 
      paramList = paramList + params[i].key + suffix; 
     } 

     return util.format("SELECT %s FROM %s", paramList, query.entity); 
    } 
}; 

這可能是去一個更清潔的方式,有一兩件事我很注意肯定的是,如果我要補充類型的原型,但我想在這止跌這個簡單的例子不需要,但是在更復雜的情況下,你可能有很多策略,並且可能需要將一個文件抽象出來。

這是一個更可接受的方法?

我最終什麼了

我環顧四周,試圖瞭解更多關於鴨子類型,優點和缺點等。並試圖根據我收到的一些評論和回答來簡化我的設計。我堅持使用策略方法,因爲每個策略都定義了相同的功能,基本上封裝了各種實現中各不相同的內容,併爲缺乏更好的術語而給予他們共同的合同。

有一點改變的是基類/接口,正如所指出的那樣,沒有任何建設性的東西被移除,每個策略都是獨立的(所以不是100%的模式的經典表示)相同的創建功能。

從嵌套的ifs和switch一次所屬的地方被替換爲一個開關,根據請求的查詢類型的類型決定使用哪種查詢策略。這可以被重新計入工廠以後,但現在它服務宗旨:

Query.prototype.generate = function() { 

var self = this, 
    strategy = undefined; 

switch (this.queryType) { 
    case "SELECT": 
     strategy = new Select(self); 
     break; 
    case "INSERT": 
     strategy = new Insert(self); 
     break; 
    case "UPDATE": 
     strategy = new Update(self); 
     break; 
    case "DELETE": 
     strategy = new Delete(self); 
     break; 
} 

return strategy.create(); 
}; 

每個戰略是獨立測試,我覺得這是更易於維護好像有什麼東西出現故障,它會失敗根據單元測試,一個地方和調查將更容易。很明顯,這是一種折衷,更多的文件和更復雜的結構......我們將看到會發生什麼。

+0

我真的不明白它的收益你,界面合同沒有執行或者通過加工,在編譯時,或在運行時。另一方面,TypeScript接口,如果你可以使用TypeScript,則執行合約(在編譯時)。 –

+0

使用鴨子鍵入 – Bergi

+0

在新的方法中,你仍然沒有獲得任何類型的安全(你不能 - 這是JavaScript)。如果你堅持在一個地方定義策略,這種方法可能會使維護變得容易一些,但是你仍然可以添加任何你想要的對象作爲類型[]的成員。這取決於我想你的目標是在這裏,執行合同(你不能 - 除了通過在運行時檢查)還是別的什麼? –

回答

7

這是一個可以接受的方法,但它不會真正有益於您,並且可能會使這段代碼更難以維護。策略模式實際上只對靜態類型的語言有用。正如另一位評論者所提到的,您可以查看TypeScript。

在JavaScript中,你將更多地依賴「鴨子打字」......如果它看起來像一隻鴨子,聞起來像鴨子,它可能是一隻鴨子。

http://en.wikipedia.org/wiki/Duck_typing

+0

鴨子打字可能是要走的路,我已經看到了使用鴨子打字來強制執行合同的界面功能的創建。 https://gist.github.com/1057989。即使在JavaScript中,我仍然認爲戰略模式是合法的。尋找一種替代方法,更新了這個問題。 – Modika

+0

接受這個,它回答了原來的問題,並指出我需要進一步閱讀。我堅持我的解決方案主要(更新上面),但基於這個答案和其他評論簡化的東西。 – Modika