Гради Буч - Объектно-ориентированный анализ и проектирование с примерами приложений на С++, страница 14
Описание файла
PDF-файл из архива "Гради Буч - Объектно-ориентированный анализ и проектирование с примерами приложений на С++", который расположен в категории "". Всё это находится в предмете "объектно-ориентированный анализ и проектирование" из 7 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Просмотр PDF-файла онлайн
Текст 14 страницы из PDF
Вязыке C++ управление доступом и видимостью более гибко. Члены класса могут быть отнесены коткрытой, закрытой или защищенной частям. Открытая часть доступна для всех объектов;закрытая часть полностью закрыта для других объектов; защищенная часть видна толькоэкземплярам данного класса и его подклассов. Кроме того, в C++ существует понятие «друзей»(friends), для которых открыта закрытая часть.Скрытие информации — понятие относительное: то, что спрятано на одном уровнеабстракции, обнаруживается на другом уровне. Забраться внутрь объектов можно; правда, обычнотребуется, чтобы разработчик класса-сервера об этом специально позаботился, а разработчикиклассов-клиентов не поленились в этом разобраться.
Инкапсуляция не спасает от глупости; она,как отметил Страуструп, «защищает от ошибок, но не от жульничества» [56]. Разумеется, языкпрограммирования тут вообще ни при чем; разве что операционная система может ограничитьдоступ к файлам, в которых описаны реализации классов. На практике же иногда простонеобходимо ознакомиться с реализацией класса, чтобы понять его назначение, особенно, если нетвнешней документации.МодульностьПонятие модульности. По мнению Майерса «Разделение программы на модули донекоторой степени позволяет уменьшить ее сложность... Однако гораздо важнее тот факт, чтовнутри модульной программы создаются множества хорошо определенных и документированныхинтерфейсов.
Эти интерфейсы неоценимы для исчерпывающего понимания программы в целом»[57]. В некоторых языках программирования, например в Smalltalk, модулей нет, и классысоставляют единственную физическую основу декомпозиции. В других языках, включая ObjectPascal, C++, Ada, CLOS, модуль — это самостоятельная языковая конструкция. В этих языкахклассы и объекты составляют логическую структуру системы, они помещаются в модули,образующие физическую структуру системы. Это свойство становится особенно полезным, когдасистема состоит из многих сотен классов.Согласно Барбаре Лисков «модульность — это разделение программы на фрагменты,которые компилируются по отдельности, но могут устанавливать связи с другими модулями».
Мыбудем пользоваться определением Парнаса: «Связи между модулями — это их представления друго друге» [58]. В большинстве языков, поддерживающих принцип модульности каксамостоятельную концепцию, интерфейс модуля отделен от его реализации. Таким образом,модульность и инкапсуляция ходят рука об руку. В разных языках программированиямодульность поддерживается по-разному. Например, в C++ модулями являются раздельнокомпилируемые файлы. Для C/C++ традиционным является помещение интерфейсной частимодулей в отдельные файлы с расширением .h (так называемые файлы-заголовки).
Реализация, тоесть текст модуля, хранится в файлах с расширением .с (в программах на C++ часто используютсярасширения .ее, .ср и .срр). Связь между файлами объявляется директивой макропроцессора#include. Такой подход строится исключительно на соглашении и не является строгим требованием самого языка.
В языке Object Pascal принцип модульности формализован несколько строже. Вэтом языке определен особый синтаксис для интерфейсной части и реализации модуля (unit). ЯзыкAda идет еще на шаг дальше: модуль (называемый package) также имеет две части —спецификацию и тело. Но, в отличие от Object Pascal, допускается раздельное определение связейс модулями для спецификации и тела пакета. Таким образом, допускается, чтобы тело модуля имело связи с модулями, невидимыми для его спецификации.Правильное разделение программы на модули является почти такой же сложной задачей,как выбор правильного набора абстракций. Абсолютно прав Зелько-виц, утверждая: «поскольку вначале работы над проектом решения могут быть неясными, декомпозиция на модули можетвызвать затруднения. Для хорошо известных приложений (например, создание компиляторов) этотпроцесс можно стандартизовать, но для новых задач (военные системы или управление космическими аппаратами) задача может быть очень трудной» [59].Модули выполняют роль физических контейнеров, в которые помещаются определенияклассов и объектов при логическом проектировании системы.
Такая же ситуация возникает упроектировщиков бортовых компьютеров. Логика электронного оборудования может бытьпостроена на основе элементарных схем типа НЕ, И-НЕ, ИЛИ-НЕ, но можно объединить такиесхемы в стандартные интегральные схемы (модули), например, серий 7400, 7402 или 7404.Для небольших задач допустимо описание всех классов и объектов в одном модуле.Однако для большинства программ (кроме самых тривиальных) лучшим решением будетсгруппировать в отдельный модуль логически связанные классы и объекты, оставив открытыми теэлементы, которые совершенно необходимо видеть другим модулям. Такой способ разбиения намодули хорош, но его можно довести до абсурда. Рассмотрим, например, задачу, котораявыполняется на многопроцессорном оборудовании и требует для координации своей работымеханизм передачи сообщений. В больших системах, подобных описываемым в главе 12,Модульность позволяет хранить абстракции раздельновполне обычным является наличие нескольких сотен и даже тысяч видов сообщений.
Было бынаивным определять каждый класс сообщения в отдельном модуле. При этом не только возникаеткошмар с документированием, но даже просто поиск нужных фрагментов описания становитсячрезвычайно труден для пользователя. При внесении в проект изменений потребуетсямодифицировать и перекомпилировать сотни модулей. Этот пример показывает, что скрытиеинформации имеет и обратную сторону [60]. Деление программы на модули бессистемнымобразом иногда гораздо хуже, чем отсутствие модульности вообще.В традиционном структурном проектировании модульность — это искусство раскладыватьподпрограммы по кучкам так, чтобы в одну кучку попадали подпрограммы, использующие другдруга или изменяемые вместе.
В объектно-ориентированном программировании ситуациянесколько иная: необходимо физически разделить классы и объекты, составляющие логическуюструктуру проекта.На основе имеющегося опыта можно перечислить приемы и правила, которые позволяютсоставлять модули из классов и объектов наиболее эффективным образом. Бритон и Парнассчитают, что «конечной целью декомпозиции программы на модули является снижение затрат напрограммирование за счет независимой разработки и тестирования.
Структура модуля должнабыть достаточно простой для восприятия; реализация каждого модуля не должна зависеть отреализации других модулей; должны быть приняты меры для облегчения процесса внесенияизменений там, где они наиболее вероятны» [61]. Прагматические соображения ставят пределэтим руководящим указаниям. На практике перекомпиляция тела модуля не является трудоемкойоперацией: заново компилируется только данный модуль, и программа перекомпонуется.Перекомпиляция интерфейсной части модуля, напротив, более трудоемка. В строготипизированных языках приходится перекомпилировать интерфейс и тело самого измененногомодуля, затем все модули, связанные с данным, модули, связанные с ними, и так далее по цепочке.В итоге для очень больших программ могут потребоваться многие часы на перекомпиляцию (еслитолько среда разработки не поддерживает фрагментарную компиляцию), что явно нежелательно.Поэтому следует стремиться к тому, чтобы интерфейсная часть модулей была возможно болееузкой (в пределах обеспечения необходимых связей).
Наш стиль программирования требуетскрыть все, что только возможно, в реализации модуля. Постепенный перенос описаний изреализации в интерфейсную часть гораздо менее опасен, чем «вычищение» избыточногоинтерфейсного кода.Таким образом, программист должен находить баланс между двумя противоположнымитенденциями: стремлением скрыть информацию и необходимостью обеспечения видимости техили иных абстракций в нескольких модулях. Парнас, Клеменс и Вейс предложили следующееправило: «Особенности системы, подверженные изменениям, следует скрывать в отдельныхмодулях; в качестве межмодульных можно использовать только те элементы, вероятностьизменения которых мала.