|
Рассмотрим первый из указанных моментов - игнорирование классов.
В таком случае получившаяся программа на С++ будет приблизительно
эквивалентна С-программе, разработанной по тому же проекту, и,
можно сказать, что они будут приблизительно эквивалентны программам
на Аде или Коболе, разработанным по нему же.
По сути проект составлен как независящий от языка реализации, что
принуждает программиста ограничиваться общим подмножеством языков
С, Ада или Кобол. Здесь есть свои преимущества. Например, получившееся
в результате строгое разделение данных и программного кода позволяет
легко использовать традиционные базы данных, которые разработаны
для таких программ. Поскольку используется ограниченный язык
программирования, от программистов требуется меньше опытности
(или, по крайней мере другой ее уровень). Для многих приложений,
например, для традиционных баз данных, работающих с
файлом последовательно, такой подход вполне разумен, а традиционные
приемы, отработанные за десятилетия, вполне адекватны задаче.
Однако там, где область приложения существенно отличается от
традиционной последовательной обработки записей (или символов),
или сложность задачи выше, как, например, в диалоговой системе
CASE, недостаток языковой поддержки абстрактных данных
из-за отказа от классов (если их не учитывать) повредит
проекту. Сложность задачи не уменьшится, но, поскольку система
реализована на обедненном языке, структура программы плохо будет
отвечать проекту. У нее слишком большой объем, не хватает проверки типов,
и, вообще, она плохо приспособлена для использования различных
вспомогательных средств. Это путь, приводящий к кошмарам при ее
сопровождении.
Обычно для преодоления указанных трудностей создают специальные
средства, поддерживающие понятия, используемые в проекте. Благодаря
им создаются конструкции более высокого
уровня и организуются проверки с целью компенсировать дефекты
(или сознательное обеднение) языка реализации. Так метод
проектирования становится самоцелью, и для него создается специальный
язык программирования. Такие языки программирования в большинстве
случаев являются плохой заменой широко распространенных языков
программирования общего назначения, которые сопровождаются
подходящими средствами проектирования. Использовать С++ с таким
ограничением, которое должно компенсироваться при проектировании
специальными средствами, бессмысленно. Хотя несоответствие между
языком программирования и средствами проектирования может быть просто
стадией процесса перехода, а значит временным явлением.
Самой типичной причиной игнорирования классов при проектировании
является простая инерция. Традиционные языки программирования не
предоставляют понятия класса, и в традиционных методах проектирования
отражаются этот недостаток. Обычно в процессе проектирования
наибольшее внимание уделяется разбиению задачи на процедуры,
производящие требуемые действия. В главе 1 это понятие называлось
процедурным программированием, а в области проектирования оно
именуется как функциональная декомпозиция. Возникает типичный
вопрос "Можно ли использовать С++ совместно с методом проектирования,
базирующимся на функциональной декомпозиции?" Да, можно, но,
вероятнее всего, в результате вы придете к использованию С++ как
просто улучшенного С со всеми указанными выше проблемами. Это
может быть приемлемо на период перехода на новый язык, или для
уже завершенного проектирования, или для подзадач, в которых
использование классов не дает существенных выгод (если учитывать
опыт программирования на С++ к данному моменту), но в общем
случае на большом отрезке времени отказ от свободного
использования классов, связанный с методом функциональной
декомпозиции, никак не совместим с эффективным использованием С++.
Процедурно-ориентированный и объектно-ориентированный
подходы к программированию различаются по своей сути и обычно
ведут к совершенно разным решениям одной задачи. Этот вывод
верен как для стадии реализации, так и для стадии проектирования:
вы концентрируете внимание или на предпринимаемых действиях, или на
представляемых сущностях, но не на том и другом одновременно.
Тогда почему метод объектно-ориентированного проектирования
предпочтительнее метода функциональной декомпозиции?
Главная причина в том, что функциональная декомпозиция не дает
достаточной абстракции данных. А отсюда уже следует, что проект
будет
Дело в том, что функциональная декомпозиция вынуждает объявлять "важные" данные глобальными, поскольку, если система структурирована как дерево функций, всякое данное, доступное двум функциям, должно быть глобальным по отношению к ним. Это приводит к тому, что "важные" данные "всплывают" к вершине дерева, по мере того как все большее число функций требует доступа к ним*.
* В точности так же происходит в случае иерархии классов с одним корнем, когда "важные" данные всплывают по направлению к базовому классу.
Когда мы концентрируем внимание на описаниях классов, заключающих
определенные данные в оболочку, то зависимости между различными
частями программы выражены явно и можно их проследить. Еще более
важно то, что при таком подходе уменьшается число зависимостей
в системе за счет лучшей расстановки ссылок на данные.
Однако, некоторые задачи лучше решаются с помощью набора
процедур. Смысл "объектно-ориентированного" проектирования не в
том, чтобы удалить все глобальные процедуры из программы или
не иметь в системе процедурно-ориентированных частей. Основная
идея скорее в том, что классы, а не глобальные процедуры становятся
главным объектом внимания на стадии проектирования. Использование
процедурного стиля должно быть осознанным решением, а не решением,
принимаемым по умолчанию. Как классы, так и процедуры следует
применять сообразно области приложения, а не просто как
неизменные методы проектирования.