понедельник, 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; } );

Комментариев нет:

Отправить комментарий