- •0. Введение: о курсе: версия для печати и pda
- •1.2 Парадигмы программирования
- •1.2.1 Процедурное программирование
- •1.2.5 Объектно-ориентированное программирование
- •1.5.1 Механизм вызова
- •1.5.3 Множественное наследование
- •1.6 Пределы совершенства
- •2. Лекция: Описания и константы: версия для печати и pda
- •2.2 Имена
- •2.3.2 Неявное преобразование типа
- •2.4 Литералы
- •2.4.4 Строки
- •2.6. Экономия памяти
- •2.6.1 Поля
- •3.1.1 Анализатор
- •3.1.2 Функция ввода
- •3.2 Сводка операций
- •3.2.3 Инкремент и декремент
- •3.2.5 Преобразование типа
- •3.2.6 Свободная память
- •3.3.2 Оператор goto
- •4.3.1 Единственный заголовочный файл
- •4.3.2 Множественные заголовочные файлы
- •4.4 Связывание с программами на других языках
- •5.3.1 Альтернативные реализации
- •5.3.2 Законченный пример класса
- •5.5.3 Свободная память
- •5.5.5 Массивы объектов класса
- •6. Лекция: Производные классы: версия для печати и pda
- •6.1 Введение и краткий обзор
- •6.2.3 Иерархия классов
- •6.2.4 Поля типа
- •6.4.1 Монитор экрана
- •6.5 Множественное наследование
- •7.3 Пользовательские операции преобразования типа
- •7.3.2 Операции преобразования
- •7.3.3 Неоднозначности
- •7.5 Большие объекты
- •Int size; // размер вектора, на который указывает p
- •7.13 Предостережения
- •7.14 Упражнения
- •8. Лекция: Шаблоны типа: версия для печати и pda
- •8.1 Введение
- •8.3.2 Список без принудительной связи
- •8.4.4 Неявная передача операций
- •8.4.5 Введение операций с помощью параметров шаблонного класса
- •8.7.1 Задание реализации с помощью параметров шаблона
- •9.1.2 Другие точки зрения на особые ситуации
- •9.3.2 Производные особые ситуации
- •9.4.2 Предостережения
- •9.4.3 Исчерпание ресурса
- •9.9 Упражнения
- •10.1 Введение
- •10.2 Вывод
- •10.2.1 Вывод встроенных типов
- •10.4.1.2 Поля вывода
- •10.4.1.4 Вывод целых
- •10.5.1 Закрытие потоков
- •10.5.2 Строковые потоки
- •X Целый параметр выдается в шестнадцатеричной записи;
- •11. Лекция: Проектирование и развитие: версия для печати и pda
- •11.1 Введение
- •11.2 Цели и средства
- •11.3 Процесс развития
- •11.3.1 Цикл развития
- •11.3.2 Цели проектирования
- •11.3.3 Шаги проектирования
- •11.3.3.1 Шаг 1: определение классов
- •11.3.3.2 Шаг 2: определение набора операций
- •11.3.3.3 Шаг 3: указание зависимостей
- •11.3.3.4 Шаг 4: определение интерфейсов
- •11.3.3.5 Перестройка иерархии классов
- •11.3.3.6 Использование моделей
- •11.3.4 Эксперимент и анализ
- •11.3.5 Тестирование
- •11.3.6 Сопровождение
- •11.3.7 Эффективность
- •11.4 Управление проектом
- •11.4.1 Повторное использование
- •11.4.2 Размер
- •11.4.3 Человеческий фактор
- •11.5 Свод правил
- •11.6 Список литературы с комментариями
- •12.1.1 Игнорирование классов
- •12.1.2 Игнорирование наследования
- •12.1.3 Игнорирование статического контроля типов
- •12.1.4 Гибридный проект
- •12.2 Классы
- •12.2.1 Что представляют классы?
- •12.2.2 Иерархии классов
- •12.2.3 Зависимости в рамках иерархии классов.
- •12.2.7 Отношения внутри класса
- •12.3 Компоненты
- •12.4 Интерфейсы и реализации
- •12.5 Свод правил
- •13. Лекция: Проектирование библиотек: версия для печати и pda
- •13.1 Введение
- •13.2 Конкретные типы
- •13.5.1 Информация о типе
- •13.6 Обширный интерфейс
- •13.7 Каркас области приложения
- •13.8 Интерфейсные классы
- •13.10 Управление памятью
11.3.3.3 Шаг 3: указание зависимостей
Уточните определение классов, указав их зависимости от других классов. Различные виды зависимостей обсуждаются в §12.2. Основными по отношению к проектированию следует считать отношения наследования и использования. Оба предполагают понимание того, что значит для класса отвечать за определенное свойство системы. Отвечать за что-либо не означает, что класс должен содержать в себе всю информацию, или, что его функции-члены должны сами проводить все необходимые операции. Как раз наоборот, каждый класс, имеющий определенный уровень ответственности, организует работу, перепоручая ее в виде подзадач другим классам, которые имеют меньший уровень ответственности. Но надо предостеречь, что злоупотребление этим приемом приводит к неэффективным и плохо понимаемым проектам, поскольку происходит размножение классов и объектов до такой степени, что вместо реальной работы производится только серия запросов на ее выполнение. То, что можно сделать в данном месте, следует сделать.
Необходимость учесть отношения наследования и использования на этапе проектирования (а не только в процессе реализации) прямо вытекает из того, что классы представляют определенные понятия. Отсюда также следует, что именно компонент (т.е. множество связанных классов), а не отдельный класс, являются единицей проектирования.
11.3.3.4 Шаг 4: определение интерфейсов
Определите интерфейсы классов. На этой стадии проектирования не нужно рассматривать приватные функции. Вопросы реализации, возникающие на стадии проектирования, лучше всего обсуждать на шаге 3 при рассмотрении различных зависимостей. Более того, существует золотое правило: если класс не допускает по крайней мере двух существенно отличающихся реализаций, то что-то явно не в порядке с этим классом, это просто замаскированная реализация, а не представление абстрактного понятия. Во многих случаях для ответа на вопрос: "Достаточно ли интерфейс класса независим от реализации?"- надо указать, возможна ли для класса схема ленивых вычислений.
Отметим, что общие базовые классы и друзья (friend) являются частью общего интерфейса класса (см. §5.4.1 и §12.4). Полезным упражнением может быть определение раздельного интерфейса для классов-наследников и всех остальных классов с помощью разбиения интерфейса на общую и закрытые части.
Именно на этом шаге следует продумать и описать точные определения типов аргументов. В идеале желательно иметь максимальное число интерфейсов со статическими типами, относящимися к области приложения (см. §12.1.3 и §12.4).
При определении интерфейсов следует обратить внимание на те классы, где набор операций представлен более, чем на одном уровне абстракции. Например, в классе file у некоторых функций-членов аргументы имеют тип file_descriptor (дескриптор_файла), а у других аргументы - строка символов, которая обозначает имя файла. Операции с file_descriptor работают на другом уровне (меньшем) абстракции, чем операции с именем файла, так что даже странно, что они относятся к одному классу. Возможно, было бы лучше иметь два класса: один представляет понятие дескриптора файла, а другой - понятие имени файла. Обычно все операции класса должны представлять понятия одного уровня абстракции. Если это не так, то стоит подумать о реорганизации и его, и связанных с ним классов.
