Основы объектно-ориентированного программирования - Бертран Мейер
Шрифт:
Интервал:
Закладка:
Аналогично АТД, класс - это тип, описывающий множество возможных структур данных, называемых экземплярами (instances) класса. Экземпляры АТД являются абстракциями - элементами математического множества. Экземпляр класса конкретен - это структура данных, размещаемая в памяти компьютера и обрабатываемая программой.
Например, если определить класс STACK, взяв за основу спецификацию АТД из предыдущей лекции и добавив информацию, необходимую для адекватного представления, то экземплярами класса будут структуры данных - конкретные стеки. Другим примером является класс POINT, моделирующий точку на плоскости. Если для представления точки выбрана декартова система координат, то каждый экземпляр POINT представляет собой запись с полями x, y - абсциссой точки и ее ординатой.
Термин "объект" появляется как побочный продукт определения "класса". Объект это просто экземпляр некоторого класса.
Программные тексты, описывающие создаваемую систему, содержат определения классов. Объекты создаются только в процессе выполнения программ.
Настоящая лекция посвящена основным приемам создания программных элементов и объединения их в системы, именно поэтому в центре внимания - классы. В следующей лекции будут рассмотрены структуры периода выполнения, порождаемые ОО-системой, что потребует изучения некоторых особенностей реализации и более детального рассмотрения природы объектов.
Устранение традиционной путаницы
Класс - это модель, а объект - экземпляр такой модели. Эта особенность настолько очевидна, что обычно не требует дополнительных комментариев. Тем не менее, в определенной категории специальной литературы имеет место весьма небрежное обращение с этими понятиями, - смешиваются понятие отдельного объекта и концепция объектов в целом, которую характеризует класс. У этой путаницы два источника. Один - возникает из-за широкого толкования термина "объект" в естественном языке. Другой источник недоразумений связан с метаклассами, - с ситуациями, когда классы сами выступают в роли объектов. Классическим примером может служить транслятор объектного языка, для которого классы языка являются объектами трансляции.
Некоторые ОО-языки, особенно Smalltalk, для выхода из рассмотренной ситуации используют понятие метакласс (metaclass). Метакласс - это класс, экземпляры которого сами являются классами. В романе "Имя Розы", отрывок из которого приведен в эпиграфе к данной лекции, встречается понятие "знаки знаков". По сути, это и есть неформальное определение метаклассов.
Мы будем избегать введения метаклассов, поскольку создаваемых ими проблем больше, чем тех, которые они решают. В частности, введение метаклассов создает трудности при проведении статической проверки типов, что является необходимым условием разработки надежного ПО. Основные функции метаклассов могут быть гораздо лучше реализованы с помощью других средств:
[x]. Метаклассы можно использовать для задания свойств, доступных многим или всем классам. Тот же результат можно достичь, создавая семейство классов, наследников общего предка - класса ANY, содержащего объявления универсальных свойств.
[x]. Некоторые операции характерны, скорее, для класса в целом, а не для отдельных его экземпляров, так что их можно рассматривать как методы метакласса. Но этих операций обычно немного и они хорошо известны. Опять-таки, их можно ввести при определении класса ANY, или реализовать введением специальных языковых конструкций. Наиболее очевидным примером является конструктор класса, выполняющий операцию создания объектов.
[x]. Метакласс может использоваться для получения дополнительной информации о классе - имени, списке свойств, списке родителей и т.д. Но и здесь нет необходимости в метаклассе. Достаточно разработать специальный библиотечный класс E_CLASS, экземпляры которого представляют классы и их свойства. При создании такого экземпляра необходимо передать в качестве параметра соответствующий класс C и далее использовать этот экземпляр для получения информации о классе C, обращаясь к соответствующим компонентам E_CLASS.
В данной книге не используется самостоятельная концепция метакласса. Присутствие метаклассов в том или ином языке или среде разработки не оправдывает смешение понятий моделей и их экземпляров - классов и объектов.
Роль классов
Затратив немного времени на устранение абсурдных, но распространенных и вредных заблуждений, можно вернуться к рассмотрению центральных свойств классов и выяснить, в частности, почему они столь важны в объектной технологии.
Для понимания ОО-подхода необходимо ясно представлять, что классы выполняют две функции, которые до появления ОО-технологий всегда были разделены. Класс одновременно является модулем и типом.
Модули и типы
Средства, используемые при разработке ПО, - языки программирования, проектирования, спецификаций, графические системы обозначений для анализа, - всегда включали в себя как возможность применения модулей, так и систему типов.
Модули - это структурные единицы, из которых состоит программа. Различные виды модулей, такие как подпрограммы и пакеты, рассматривались в одной из предыдущих лекций (см. лекция 3). Независимо от конкретного выбора той или иной модульной структуры, модуль всегда рассматривается как синтаксическая концепция. Отсюда следует, что разбиение на модули влияет лишь на форму записи исходных текстов программ, но не определяет их функциональность. В самом деле, принципиально можно написать программу Ada в виде единственного пакета, или программу Pascal как единую основную программу. Безусловно, такой подход не рекомендуется, и любой компетентный программист будет использовать модульные возможности языка для деления программы на обозримые и управляемые части. Но если взять существующую программу, например на Паскале, то всегда можно собрать воедино все модули и получить работоспособную программу с эквивалентной семантикой. (Присутствие рекурсивных подпрограмм делает этот процесс менее тривиальным, но не оказывает принципиального влияния на данную дискуссию.) Таким образом, деление на модули диктуется принципами управления проектами, а не внутренней необходимостью.
Концепция типов на первый взгляд совершенно иная. Тип является статическим описанием вполне определенных динамических объектов - элементов данных, которые обрабатываются во время выполнения программной системы. Набор типов обычно содержит предопределенные типы, такие как INTEGER или CHARACTER, а также пользовательские типы: записи (структуры), указатели, множества (в Pascal), массивы и другие. Понятие типа является семантической концепцией, и каждый тип непосредственно влияет на выполнение программной системы, так как описывает форму объектов, которые система создает и которыми она манипулирует.
Класс как модуль и как тип
В не ОО-подходах концепции модуля и типа существуют независимо друг от друга. Наиболее замечательным свойством класса является одновременное использование обеих концепций в рамках единой лингвистической конструкции. Класс является модулем или единицей программной декомпозиции, но одновременно класс это тип (или шаблон типа в тех случаях, когда поддерживается параметризация).
Мощь ОО-метода, во многом, следствие этого отождествления. Наследование, в частности, может быть полностью понято только при рассмотрении его, как модульного расширения, так и, одновременно, уточнения специализации типа.
Как практически соединить две столь различные на первый взгляд концепции? Последующая дискуссия и примеры позволят ответить на этот вопрос.
Унифицированная система типов
Важным аспектом ОО-подхода является простота и универсальность системы типов, которая строится на основе фундаментального принципа.
Объектный принцип
Каждый объект является экземпляром некоторого класса
Объектный принцип будет распространяться не только на составные объекты, определяемые разработчиками (такие как структуры данных, содержащие несколько полей), но и на базовые объекты - целые и действительные числа, булевы значения и символы, которые будут рассматриваться как экземпляры предопределенных библиотечных классов (INTEGER, REAL, DOUBLE, BOOLEAN, CHARACTER).
На первый взгляд подобное стремление превратить любое сколь угодно простое значение в экземпляр некоторого класса может показаться преувеличенным и даже экстравагантным. В конце концов, математики и инженеры в течение многих лет успешно используют целые и действительные числа, не подозревая о том, что они работают с экземплярами классов. Однако настойчивое требование к унификации вполне окупается по ряду причин.