}
});
}());
В заключение хотелось бы подчеркнуть, что возможность создания подобных фабрик классов обусловлена динамической природой языка JavaScript. Фабрики классов представляют собой мощный и гибкий инструмент, не имеющий аналогов в языках, подобных Java и C++.
9.7.3. Композиция в сравнении с наследованием
В предыдущем разделе мы решили определить класс множеств, накладывающий ограничения на свои элементы в соответствии с некоторыми критериями, а для достижения поставленной цели использовали механизм наследования, определив функцию создания специализированного подкласса указанной реализации множества, использующего указанную функцию-фильтр для ограничения круга допустимых элементов множества. При таком подходе для каждой комбинации суперкласса и функции-фильтра необходимо создавать новый класс.
Однако существует более простой путь решения этой задачи. В объектно-ориентированном программировании существует известный принцип «предпочтения композиции перед наследованием». [18] См. Э. Гамма и др. «Приемы объектно-ориентированного проектирования. Паттерны проектирования» или Дж. Блох «Java. Эффективное программирование».
В данном случае применение приема композиции могло бы выглядеть как реализация нового множества, «обертывающего» другой объект множества и делегирующего ему все обращения после фильтрации нежелательных элементов. Пример 9.15 демонстрирует, как это реализовать.
Пример 9.15. Композиция множеств вместо наследования
/*
* Объект FilteredSet обертывает указанный объект множества и применяет
* указанный фильтр в своем методе add(). Обращения ко всем остальным базовым
* методам просто передаются обернутому экземпляру множества.
*/
var FilteredSet = Set.extend(
function FilteredSet(set, filter) { // Конструктор
this.set = set; this.filter = filter;
},
{ // Методы экземпляров
add: function() {
// Если фильтр был указан, применить его
if (this.filter) {
for(var і = 0; і < arguments.length; i++) {
var v = arguments[i];
if (!this.filter(v))
throw new Error("FilteredSet: значение " + v + " отвергнуто фильтром");
}
}
// Затем вызвать метод add() объекта
this.set.add() this.set.add.apply(this.set, arguments);
return this;
},
// Остальные методы просто вызывают соответствующие
// методы объекта this.set и ничего более,
remove: function() {
this.set.remove.apply(this.set, arguments);
return this;
}.
contains: function(v) {
return this.set.contains(v);},
size: function() { return this.set.size(); },
foreach: function(f,c) { this.set.foreach(f.c); }
}
)
Одно из преимуществ применения приема композиции в данном случае заключается в том, что требуется определить только один подкласс FilteredSe
t. Экземпляры этого класса могут накладывать ограничения на элементы любого другого эк» земпляра множества. Например, вместо класса NonNullSet
, представленного выше, реализовать подобные ограничения можно было бы так:
var s = new FilteredSet(new Set(), function(x) { return x !== null; });
Можно даже наложить еще один фильтр на фильтрованное множество:
var t = new FilteredSet(s, { function(x) { return !(x instanceof Set); });
9.7.4. Иерархии классов и абстрактные классы
В предыдущем разделе было предложено «предпочесть композицию наследованию». Но для иллюстрации этого принципа мы создали подкласс класса Set
. Сделано это было для того, чтобы получившийся подкласс был instanceof Set
и наследовал полезные методы класса Set
, такие как toString()
и equals().
Это достаточно уважительные причины, но, тем не менее, было бы неплохо иметь возможность использовать прием композиции без необходимости наследовать некоторую определенную реализацию множества, такую как класс Set
. Аналогичный подход можно было бы использовать и при создании класса SingletonSet
(пример 9.12) -этот класс был определен как подкласс класса Set
, чтобы унаследовать вспомогательные методы, но его реализация существенно отличается от реализации суперкласса. Класс SingletonSet
- это не специализированная версия класса Set
, а совершенно иной тип множеств. В иерархии классов SingletonSet
должен был бы находиться на одном уровне с классом Set
, а не быть его потомком.
Читать дальше
Конец ознакомительного отрывка
Купить книгу