Я пишу код в 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;
В настоящее время база не имеет общих функций или свойств. Общие функции придут, свойства, из-за прототипного поиска цепи я не видел смысла добавления "общих" свойств, поскольку они перезаписываются созданными экземплярами (пожалуйста, если это неправильно, сообщите мне).
Является ли это приемлемым подходом или я должен игнорировать наследование в этом случае. Там может быть какая-то проверка типа, и было бы проще, если бы вы могли сделать вывод этого типа (т.е. Все они должны быть типа QueryStrategy), но я не хочу, чтобы мой .Net-предрассудок занял здесь.
Альтернативный подход
Во-первых, я не пытаюсь продавать книги здесь, я просто много читаю о предмете с книгами, которые у меня есть, но хочу отдать должное там, где это необходимо.
Основываясь на нескольких комментариях, правильно сказать, что вывод типа на самом деле не имеет никакого значения здесь и, возможно, должен быть оставлен до Duck Typing, чтобы проверить, и, возможно, попытаться сложить что-то в этом нет. определенный на языке, не лучший подход. Я прочитал в Ady Osmani шаблоны Javascript об интерфейсах, хотя моя реализация была не такой, и хотя использование интерфейса приемлемо, вероятно, это не нужно.
Может быть проще сохранить стратегический подход, но с другой реализацией, описанной в шаблонах Javascript Stoyan Stefanov, где у вас есть одна реализация и на основе какой-то конфигурации вы знаете, какую стратегию использовать.
Псевдо выборка
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 typing, "за" и "против" и т.д. и попытался упростить мой дизайн, основываясь на некоторых комментариях и ответах, которые я получил. Я придерживался стратегического подхода, так как каждая стратегия определяла ту же функцию (ы), которая в значительной степени инкапсулировала то, что варьировалось во всех реализациях, и давало им общий контракт из-за отсутствия лучшего термина.
Одной из вещей, которые были изменены, был базовый класс/интерфейс, который, как правильно указал, не делал ничего конструктивного, удалялся, каждая стратегия независима (а значит, не 100% в классическом представлении шаблона) они, как указано, просто определяют та же функция создания.
От места, где вложенные элементы ifs и переключатели некогда принадлежали, был заменен одним коммутатором, который решает, какую стратегию запроса использовать в зависимости от типа запрашиваемого типа запроса. В дальнейшем это может быть переопределено в factory, но пока оно служит своей цели:
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();
};
Каждая стратегия проходит независимую проверку, и я чувствую, что ее легче поддерживать, как будто что-то не удается, она не срабатывает в одном месте, и расследование будет проще на основе модульных тестов. Очевидно, что есть компромисс, больше файлов и немного более сложная структура... мы увидим, что произойдет.