|
Программирование >> Решение нетривиальных задач
Возвращаясь вновь к печати, отметим, что соответствующим сообщением могло бы быть воспроизвести себя на этом устройстве , а обработчику сообщения могла быть передана ссылка на обобщенный объект device, которому нужно переслать данные. Код, который фактически выполняет воспроизведение, на самом деле находится внутри этого объекта. (В порядке разъяснения: нет причины, из-за которой нельзя поддерживать несколько сообщений типа воспроизведи себя . Например, объект электронной таблицы мог бы поддерживать сообщения воспроизвести себя в виде таблицы , воспроизвести себя в виде графика и воспроизвести себя в виде круговой диаграммы ). В структурной системе код, который выполняет воспроизведение, является внешним. Некая функция получает откуда-то объект, после чего делает различные системные вызовы для вывода его на экран. Если вы говорите о printf() , то вызовы не очень сложные, но если речь заходит о Windows или Motif - у вас появляется проблема. Объектно-ориентированный проект фактически является вывернутым наизнанку в сравнении со структурным проектом. Преимущество объектно-ориентированного подхода - в том, что вы можете менять операционную среду путем изменения реализации объекта device, и при этом остальной код в программе не затрагивается. Несмотря на это, вызванные изменения столь фундаментальны, что полный перевод возможен лишь после переработки в программе каждой функции, которая прямо вызывает функцию операционной системы. Это нетривиальное мероприятие, которое вероятно потребует отбрасывания большей части кода в существующем приложении. Сообщение модифицировать себя аналогично: диалоговое окно модификации в стандартной структурной программе изображается внешним кодом. В объектно-ориентированном проекте объект сам взаимодействует с пользователем в ответ на получение сообщения модифицировать себя - наизнанку в сравнении со структурным подходом. И снова преимущество в том, что изменения полей, которые должны быть модифицированы, концентрируются в определении класса. Вам не нужно искать по всей программе код, который использует объекты класса, каждый раз, когда меняется поле в определении класса. Мой опыт с гибридными приложениями не очень удачен: кажется, что в них соединяются все проблемы как структурных, так и объектно-ориентированных систем без каких то преимуществ тех и других. Это реальная опасность для тех, у кого нет времени, чтобы делать все правильно - они могут получить в итоге несопровождаемый гибрид. Ошибочно рассматривать тело существующего кода, вне зависимости от его размера, в качестве ценного имущества , в которое вы должны постоянно инвестировать. Вы не выбросите деньги, потраченные на написание существующего кода, когда решитесь от него отказаться. Деньги, потраченные на написание кода, уже, наверное, окупились за счет продаж, и теперь, чтобы чего-то достичь, вы должны не дорабатывать существующий код, а писать новый. Начинающая фирма-конкурент, способная лишь куснуть вас за пятку, разрабатывает свой продукт с самого начала и получает преимущество за счет использования современной технологии и идей по методологии проектирования. Между тем ваш существующий код запирает вас в рамках обветшалого проекта и устаревшей технологии. Нельзя просто откинуться на спинку кресла и почить на лаврах - вы должны постоянно переписывать свой продукт заново, чтобы совершенствовать его сколь-нибудь заметным образом. Я должен сказать, что многие со мной в этом месте не согласны. Рецензент одной из моих недавних статей ответил на (возможно, слишком упрощенное) утверждение, что гибридные приложения не работают , заявив: Я знаю массу торгово-транспортных приложений, которые написаны именно таким образом, приносят прибыль своим создателям и, следовательно, работают . С другой стороны, тот факт, что этот рецензент работает в фирме, владеющей несколькими огромными гибридными приложениями, очевидно, повлиял на его отзыв. Один из этих гибридов задерживался с выходом на рынок более чем на год во время, когда писалась рецензия, и сопровождение было постоянным кошмаром для большинства остальных, но я думаю, что эти проблемы были недостаточно важными, чтобы их учитывать, потому что этот конкретный программист не занимался сопровождением. 96. Объект производного класса является объектом базового класса 97. Наследование - это процесс добавления полей данных и методов-членов В Си++ производный класс может рассматриваться как механизм добавления полей данных и обработчиков сообщений к существующему определению класса - к базовому классу. (Вы можете также смотреть на наследование как на средство изменения поведения объекта базового класса при получении им конкретного сообщения. Я вернусь к такой точке зрения при обсуждении виртуальных функций). В таком случае иерархия классов является просто средством представления полей данных и методов, определяемых для конкретного объекта. Объект содержит все 5 Они не передаются. Даже в Smalltalk есть только один объект, который или получает сообщение, или нет. Несмотря на это, интерпретаторы Smalltalk склоняются к реализации обработки сообщений при помощи нескольких таблиц указателей на функции, по одной на каждый класс. Если интерпретатор не может найти обработчик сообщения в таблице диспетчеризации производного класса, то он просматривает таблицу базового класса. Этот механизм не используется в Си++, который является компилируемым языком и поэтому не использует многоуровневый просмотр таблиц в время выполнения. Например, даже если бы все функции в базовом классе были виртуальными, то таблица виртуальных функций производного класса имела бы по ячейке для каждой виртуальной функции базового класса. Среда времени выполнения Си++ не просматривает иерархию таблиц, а просто использует таблицу для текущего объекта. Подробнее об этом позднее. данные и методы, объявленные на его уровне, а также на всех вышележащих уровнях. Общая ошибка, совершаемая начинающими программистами на Си++, состоит в том, что они смотрят на иерархию классов и думают, что сообщения передаются от объектов производного класса к объектам базового класса. Помните, что иерархия классов Си++ не существует во время выполнения. Все, что у вас есть во время выполнения, это фактические объекты, чьи поля определяются во время компиляции при помощи иерархии классов. В этом вопросе путаница создана многими книгами по языку Smalltalk, описывающими реализацию во время выполнения системы обработки сообщений так, как если бы сообщения передавались от производного к базовому классу.5 Это просто неверно (и в случае Smalltalk, и в случае Си++). Си++ использует наследование. Производный класс - это тот же базовый класс, но с несколькими добавленными полями и обработчиками сообщений. Следовательно, когда объект Си++ получает сообщение, он или обрабатывает его, или нет; он или определяет обработчик, или получает его в наследство. Если ни то, ни другое не имеет места, то сообщение просто не может быть обработано. И оно никуда не передается. Не путайте отношение наследования с объединением. При объединении в один класс (контейнер) вложен объект другого класса (в отличие от наследования от другого класса). Объединение в действительности лучше, чем наследование, если у вас есть возможность выбора, потому что отношения сцепления между вложенным объектом и внешним миром гораздо слабее, чем отношения между базовым классом и внешним миром.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |