понедельник, 17 февраля 2014 г.
JavaScript Дублирование кода
Скорее всего, в любом API содержится множество методов-аксессоров (геттеров, сеттеров, экзекуторов), которые делают похожие вещи. Вернёмся к примеру с DateInterval. Там мы наверняка предоставили бы методы start() и end() для управления интервалами. Простое решение может выглядеть так:
DateInterval.prototype.start = function(date) {
if (date === undefined) {
return new Date(this.startDate.getTime());
}
this.startDate.setTime(date.getTime());
return this;
};
DateInterval.prototype.end = function(date) {
if (date === undefined) {
return new Date(this.endDate.getTime());
}
this.endDate.setTime(date.getTime());
return this;
};
Как видите, куча повторяющегося кода. Принцип «не повторяйся» (DRY или Don't Repeat Yourself, прим. ред.) подсказывает нам возможность воспользоваться шаблоном-генератором:
var accessors = ["start", "end"];
for (var i = 0, length = accessors.length; i < length; i++) {
var key = accessors[i];
DateInterval.prototype[key] = generateAccessor(key);
}
function generateAccessor(key) {
var value = key + "Date";
return function(date) {
if (date === undefined) {
return new Date(this[value].getTime());
}
this[value].setTime(date.getTime());
return this;
};
}
Такой подход позволит вам генерировать несколько похожих методов-аксессоров вместо того, чтобы указывать каждый из них по отдельности. Если ваши аксессоры требуют больше данных при генерации, чем просто строка, можно использовать что-то подобное:
var accessors = {"start" : {color: "green"}, "end" : {color: "red"}};
for (var key in accessors) {
DateInterval.prototype[key] = generateAccessor(key, accessors[key]);
}
function generateAccessor(key, accessor) {
var value = key + "Date";
return function(date) {
// тут делаем что-нибудь полезное,
// используя `key` и `accessor.color`
};
}
В главе Обработка аргументов мы говорили о паттерне Метод, позволяющем принимать вашим геттерам и сеттерам значения различных полезных типов, вроде словарей и массивов. Паттерн Метод сам по себе достаточно универсален, и его можно с легкостью превратить в генератор:
function wrapFlexibleAccessor(get, set) {
return function(name, value) {
var map;
if (jQuery.isPlainObject(name)) {
// устанавливаем словарь
map = name;
} else if (value !== undefined) {
// устанавливаем значение (возможно, на нескольких именах),
// преобразуем в словарь
keys = name.split(" ");
map = {};
for (var i = 0, length = keys.length; i < length; i++) {
map[keys[i]] = value;
}
} else {
return get.call(this, name);
}
for (var key in map) {
set.call(this, name, map[key]);
}
return this;
};
}
DateInterval.prototype.values = wrapFlexibleAccessor(
function(name) {
return name !== undefined
? this.values[name]
: this.values;
},
function(name, value) {
this.values[name] = value;
}
);
Подписаться на:
Комментарии к сообщению (Atom)
Комментариев нет:
Отправить комментарий