Читаем Основы объектно-ориентированного программирования полностью

Используя это отношение можно описывать схемы отношения "является", представляющие многие варианты типов, например, все варианты класса FIGURE. Каждая новая версия таких подпрограмм как rotate и display определяется в классе, задающем соответствующий вариант типа. В случае таблиц, например, каждый класс на графе обеспечивает свою собственную реализацию операций search, insert, delete, разумеется, за исключением тех случаев, когда для него подходит реализация родителя.

Предостережение об использовании отношения "является" ("is a"). Начинающие - но я полагаю, ни один из читателей, добравшийся до этого места даже с минимумом внимания, - иногда путают наследование с отношением "экземпляр - образец", считая класс SAN_FRANCISCO наследником класса CITY. Это, как правило, ошибка: CITY - это класс, у которого может быть экземпляр, представляющий Сан Франциско. Чтобы избежать таких ошибок, достаточно помнить, что термин "является" означает не "x является одним из A" (например, "Сан Франциско является городом (CITY)), т.е. отношением между экземпляром и категорией, а выражает "всякий B является A" (например, "всякий ГОРОД является ГЕОГРАФИЧЕСКОЙ_ЕДИНИЦЕЙ"), т.е. отношение между двумя категориями, в программировании - двумя классами. Некоторые авторы предпочитают называть это отношение "является разновидностью" или "может действовать как" [Gore 1996]. Отчасти это дело вкуса (и частично этот предмет будет обсуждаться в лекции о методологии наследования), но поскольку мы уже знаем, как избежать тривиальной ошибки, то будем и далее использовать наиболее распространенное название "является", не забывая при этом, что оно относится к отношению между категориями.

<p>Наследование и децентрализация</p>

Имея динамическое связывание, можно создавать децентрализованные архитектуры ПО, необходимые для достижения целей повторного использования и расширяемости. Сравним ОО-подход, при котором самодостаточные классы предоставляют свои множества вариантов операций, с классическими подходами. В Паскале или Аде можно использовать тип записи с вариантами

type FIGURE =

record

"Общие поля"

case figtype: (polygon, rectangle, triangle, circle,...) of

polygon: (vertices: LIST_OF_POINTS; count: INTEGER);

rectangle: (side1, side2: REAL;...);

...

end

чтобы определить различные виды фигур. Но это означает, что всякая программа, которая должна работать с фигурами (поворачивать и т.п.) должна проводить разбор возможных случаев:

case f.figure_type of

polygon: ...

circle: ...

...

end

В случае таблиц процедура search должна была бы использовать ту же структуру. Неприятность состоит в том, что эти процедуры должны обладать чересчур большими знаниями о будущем всей системы: они должны точно знать, какие типы фигур в ней допускаются. Любое добавление нового типа или изменение существующего будет затрагивать каждую процедуру.

Ne sutor ultra crepidam, (для сапожника ничего сверх сандалий) - это принцип разработки ПО: процедуре поворота не требуется знать полный список типов фигур. Ей должно хватать информации необходимой для выполнения своей работы: поворота некоторых видов фигур.

Распределение информации среди чересчур большого количества процедур является главным источником негибкости классических подходов к разработке ПО. Основные трудности модификации ПО можно проследить, анализируя эту проблему. Она также частично объясняет, почему так трудно управлять программными проектами, когда совсем небольшие изменения имеют далеко идущие последствия, заставляя разработчиков переделывать модули, которые, казалось бы, были успешно завершены.

ОО-методы также сталкиваются с этой проблемой. Изменение реализации операции затрагивает только тот класс, в котором применяется эта реализация. Добавление нового варианта некоторого типа в большинстве случаев не затронет другие классы. Причиной является децентрализация: классы заведуют своими собственными реализациями и не вмешиваются в дела друг друга. В применении к людям это звучало бы как Вольтеровское Cultivez votre jardin, - ухаживайте за своим собственным садом. В применении к модулям существенным является требование получения децентрализованных структур, которые изящно поддаются расширению, модификации, комбинированию и повторному использованию.

<p>Независимость от представления</p>

Динамическое связывание связано с одним из принципиальных аспектов повторного использования: независимостью от представления, т.е. возможностью запрашивать исполнение некоторой операции, имеющей несколько вариантов, не уточняя, какой из них будет применен. В предыдущей лекции при обсуждении этого понятия использовался пример вызова

Перейти на страницу:

Похожие книги