【问题标题】:Is trying to imitate a interface/abstract class in javascript bad practice试图在 javascript 不良实践中模仿接口/抽象类
【发布时间】:2012-10-19 20:00:01
【问题描述】:

我正在用 Node.js 编写一些代码,这些代码让我大吃一惊,因为使用策略模式可以更好地结构化。来自 .Net 我将创建其余部分所基于的接口并从那里移动,在 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;

目前该基础没有任何共享功能或属性。共享函数将会出现,属性,因为原型链搜索我没有看到添加“共享”属性的意义,因为它们被创建的实例覆盖(如果这是错误的,请告诉我)。

这是一种可接受的方法,还是在这种情况下我应该忽略继承。可能会有一些类型检查,如果您可以将类型推断为一个(即它们必须都是 Type QueryStrategy),那么它会更容易,但我不希望我的 .Net 偏见在这里接管。

替代方法

首先,我不是想在这里卖书,我只是在阅读有关该主题的大量书籍,但想在应得的地方给予赞扬。

基于这两个 cmets,可以正确地说类型推断在这里不会真正产生任何影响,可能应该留给 Duck Typing 来检查,也许尝试在其中插入一些不是在语言中定义不是最好的方法。我在 Addy Osmani Javascript patterns 中阅读过关于接口的内容,虽然我的实现不一样,虽然接口使用是可以接受的,但可能不需要。

保留策略方法可能更简单,但使用不同的实现方式,在 Stoyan Stefanov 的 Javascript 模式中概述了一种实现方式,您有一个实现方式,并且基于某种形式的配置,您知道要使用哪种策略。

伪样本

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);
    }
};

这可能是一种更简洁的方法,我要确定的一件事是我是否应该向原型添加类型,但我想在这种简单的情况下不需要它,但在更复杂的情况下你可能有很多策略,并且在一个文件中可能需要抽象出来。

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

我的结局

我环顾四周,试图了解更多关于 Duck 打字、优点和缺点等的信息,并尝试根据我收到的一些 cmets 和答案简化我的设计。我坚持采用类似策略的方法,因为每个策略都定义了相同的功能,本质上封装了实现中的不同之处,并为它们提供了一个通用的合同,以寻求更好的条款。

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

嵌套的 if 和 switch 曾经所属的位置已被单个 switch 替换,该 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();
};

每个策略都经过独立测试,我觉得这更容易维护,就像发生故障一样,它会在一个地方失败,并且基于单元测试进行调查会更容易。显然有一个折衷,更多的文件和稍微复杂的结构......我们会看到会发生什么。

【问题讨论】:

  • 我看不出它能给你带来什么,接口契约不是通过工具、编译时或运行时强制执行的。另一方面,TypeScript 接口,如果您可以使用 TypeScript,则强制执行合同(在编译时)。
  • 在新方法中,您仍然没有获得任何类型的安全性(您不能 - 它是 javascript)。如果您虔诚地坚持在一个地方定义策略,也许这种方法会使维护变得更容易一些,但您仍然可以添加任何您想要的对象作为 types[] 的成员。这取决于我想你的目标是什么,强制执行合同(你不能 - 除了在运行时检查)或其他什么?
  • 我不是在寻找类型安全,但我很欣赏第一种方法的样子,我只是重构一个有几个 switch case 语句、if 语句等的方法,它似乎是一种策略模式javascript 表单(我知道它不会出现)因为这就是它所依赖的。至于传递任何类型,我想我可以检查以确保它具有执行所需的功能,如果没有则返回错误。我的总体目标是可读性和编写更好的结构化代码,来自 .NET 我知道我不能直接使用这些模式。

标签: javascript oop node.js


【解决方案1】:

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

在 JavaScript 中,您将更多地依赖“Duck Typing”...如果它看起来像鸭子,闻起来像鸭子,那么它可能就是一只鸭子。

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

【讨论】:

  • Duck Typing 可能是要走的路,我已经看到创建了一个使用 Duck 类型来执行合同的接口函数。 gist.github.com/1057989。即使在 JavaScript 中,我仍然认为策略模式是合法的。查看另一种方法,更新了问题。
  • 要接受这个,它回答了原始问题,并指出我需要进一步阅读。我主要坚持我的解决方案(在上面更新),但根据这个答案和其他 cmets 简化了事情。
猜你喜欢
  • 2010-12-28
  • 1970-01-01
  • 2011-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-22
  • 2012-07-17
  • 1970-01-01
相关资源
最近更新 更多