试图在javascript不良实践中模仿接口/抽象类

Mod*_*ika 13 javascript oop node.js

我在Node.js中编写了一些代码,这些代码使用策略模式进行了更好的结构化.来自.Net我会创建其余基于的接口并从那里移动,在JavaScript中这不是那么明确.

我理解作为一种原型语言JavaScript没有接口继承的概念,所以我不确定我做了什么是有气味,因为我似乎无法找到引用,除了一篇试图推断界面的博客文章通过使用一个基本抽象类来强制继承类实现该函数(因为它抛出).

我的基类

QueryStrategy = function () {

};

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

module.exports = QueryStrategy;
Run Code Online (Sandbox Code Playgroud)

实施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;
Run Code Online (Sandbox Code Playgroud)

目前,基础没有任何共享功能或属性.共享函数将来,属性,因为原型链搜索我没有看到添加"共享"属性的点,因为它们被创建的实例覆盖(请问如果这是错误的,请告诉我).

这是一种可接受的方法,还是应该忽略这种情况下的继承.可能有一些类型检查,如果您可以将类型推断为一个(即它们必须都是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);
    }
};
Run Code Online (Sandbox Code Playgroud)

这可能是一种更清洁的方式,我要注意的一件事是我是否应该在原型中添加类型,但我想在这个简单的情况下它不需要,但在更复杂的情况下你可以有一个许多策略和一个文件可能需要抽象出来.

这是一种更可接受的方法吗?

我最终得到了什么

我环顾四周,试图更多地了解鸭子打字,优点和缺点等,并试图根据我收到的一些评论和答案简化我的设计.我坚持使用策略方法,因为每个策略都定义了相同的功能,基本上封装了各个实现的不同内容,并为需要更好的术语提供了一个共同的契约.

改变的一件事是基类/接口,如正确指出的那样没有做任何有建设性的事情被删除,每个策略都是独立的(因此在模式的经典表示中不是100%),如上所述只是定义相同的创建函数.

从嵌套的ifs和开关曾经属于的地方已被替换为单个开关,该开关根据所请求的查询类型类型决定使用哪个查询策略.这可以在以后重新计入工厂,但现在它的目的是:

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();
};
Run Code Online (Sandbox Code Playgroud)

每个策略都经过独立测试,我觉得这样更容易维护,好像有什么东西失败了,它会在一个地方失败,根据单元测试,调查会更容易.显然存在权衡,更多文件和稍微复杂的结构......我们将看到会发生什么.

Rya*_*ill 9

这是一种可接受的方法,但它并没有真正以任何方式使您受益,并且可能使这段代码更难以维护.策略模式实际上只对具有静态类型的语言有益.你可以看一下TypeScript,正如另一位评论者提到的那样.

在JavaScript中,你将更多地依赖于"Duck Typing"...如果它看起来像一只鸭子,闻起来像一只鸭子,它可能是一只鸭子.

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