Дэвид Флэнаган - JavaScript. Подробное руководство, 6-е издание
- Название:JavaScript. Подробное руководство, 6-е издание
- Автор:
- Жанр:
- Издательство:Символ-Плюс
- Год:2012
- Город:СПб
- ISBN:978-5-93286-215-5
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Дэвид Флэнаган - JavaScript. Подробное руководство, 6-е издание краткое содержание
Эта книга - одновременно и руководство программиста, и полноценный справочник по базовому языку JavaScript и клиентским прикладным интерфейсам, предоставляемым веб-броузерами.
JavaScript. Подробное руководство, 6-е издание - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
// методы объекта 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
, а не быть его потомком.
Решение этой проблемы в классических объектно-ориентированных языках, а также в языке JavaScript
заключается в том, чтобы отделить интерфейс от реализации. Представьте, что мы определили класс AbstractSet
, реализующий вспомогательные методы, такие как toString(),
в котором отсутствуют реализации базовых методов, таких как foreach().
Тогда все наши реализации множеств - Set, SingletonSet
и FilteredSet
- могли бы наследовать класс AbstractSet
. При этом классы FilteredSet
и SingletonSet
больше не наследовали бы ненужные им реализации.
Пример 9.16 развивает этот подход еще дальше и определяет иерархию абстрактных классов множеств. Класс AbstractSet
определяет только один абстрактный метод, contains().
Любой класс, который претендует на роль множества, должен будет определить хотя бы один этот метод. Далее в примере определяется класс AbstractEnumerableSet
, наследующий класс AbstractSet
. Этот класс определяет абстрактные методы size()
and foreach()
и реализует конкретные вспомогательные методы ( toString(), toArray(), equals()
и т.д.). AbstractEnumerableSet
не определяет методы add()
или remove()
и представляет класс множеств, доступных только для чтения. Класс SingletonSet
может быть реализован как конкретный подкласс. Наконец, в примере определяется класс AbstractWritableSet
, наследующий AbstractEnumerableSet
. Этот последний абстрактный класс определяет абстрактные методы add()
и remove()
и реализует конкретные методы, такие как union()
и intersection(),
использующие их. Класс AbstractWritableSet
отлично подходит на роль суперкласса для наших классов Set
и FilteredSet
. Однако они не были добавлены в пример, а вместо них была включена новая конкретная реализация с именем ArraySet
.
Пример 9.16 довольно объемен, но он заслуживает детального изучения. Обратите внимание, что для простоты создания подклассов в нем используется функция
Function.prototype.extend().
Пример 9.16. Иерархия абстрактных и конкретных классов множеств
// Вспомогательная функция, которая может использоваться для определения
// любого абстрактного метода
function abstractmethod() { throw new Error("абстрактный метод"); }
/*
* Класс AbstractSet определяет единственный абстрактный метод, contains().
*/
function AbstractSet() {
throw new Error("Нельзя создать экземпляр абстрактного класса");
}
AbstractSet.prototype.contains = abstractmethod;
/*
* NotSet - конкретный подкласс класса AbstractSet.
* Элементами этого множества являются все значения, которые не являются
* элементами некоторого другого множества. Поскольку это множество
* определяется в терминах другого множества, оно не доступно для записи,
* а так как оно имеет бесконечное число элементов, оно недоступно для перечисления.
* Все, что позволяет этот класс, - это проверить принадлежность к множеству.
* Обратите внимание, что для определения этого подкласса используется метод
* Function.prototype.extendO, объявленный выше.
*/
var NotSet = AbstractSet.extend(
function NotSet(set) { this.set = set; },
{
contains: function(x) { return !this.set.contains(x); },
toString: function(x) { return "~" + this.set.toString(); },
equals: function(that) {
return that instanceof NotSet && this.set.equals(that.set);
}
}
);
/*
* AbstractEnumerableSet - абстрактный подкласс класса AbstractSet.
* Определяет абстрактные методы size() и foreach() и реализует конкретные
* методы isEmptyO. toArrayO, to[Locale]String() и equals().
* Подклассы, реализующие методы contains(), size() и foreach(),
* получают эти пять конкретных методов даром.
*/
var AbstractEnumerableSet = AbstractSet.extend(
function() {
throw new Error("Нельзя создать экземпляр абстрактного класса");
Интервал:
Закладка: