Глобальные объекты и константы
Глобальные объекты - некий вызов ОО-методу, провозглашающему идеи децентрализации, модульности и автономности. Борьба шла за независимость модулей, за избавление от произвола центральной власти. Теперь этой власти нет. Как же построить систему, в которой компоненты совместно используют данные, не теряя своей автономности, гибкости, допускают повторное использование?
Передавать модулю разделяемые объекты как параметры не разумно, поскольку число их может быть достаточно велико. Да и сама передача параметров предполагает существование владельца, хотя при подлинном разделении владеть значениями не может ни один модуль.
Поиск более удачного решения мы начнем с хорошо известного понятия, необходимого как в объектной, так и в традиционной методологии проектирования. Речь пойдет о константах. Что такое константа Pi, как не простой, совместно используемый объект? Обобщив это понятие на более сложные объекты, мы сделаем первый шаг на пути к разделению объектов.
Константы базовых типов
Начнем с формы записи констант.
Правило стиля - принцип символических констант - гласит, что обращение к конкретному значению (числу, символу или строке) почти всегда должно быть косвенным. Должно существовать определение константы, задающее имя, играющее роль символической константы ( symbolic constant), и связанное с ним значение - константа, называемая манифестной ( manifest constant). Далее в алгоритме следует использовать символическую константу. Тому есть два объяснения.
- Читабельность: читающему текст легче понять смысл US_states_count, чем числа 50 ;
- Расширяемость: символическую константу легко обновить, исправив лишь ее определение.
Принцип допускает применение манифестных или, как часто говорят, неименованных констант в качестве "начальных" элементов разнообразных операций, как в случае с циклом from i = 1 until i > n (Но n, конечно, должно быть символической константой).
Итак, нам нужен простой и ясный способ определения символических констант.
Атрибуты-константы
Как и все сущности, символические константы должны быть определены внутри класса. Будем рассматривать константы как атрибуты с фиксированным значением, одинаковым для всех экземпляров класса.
Синтаксически вновь используем служебное слово is, применяемое при описании методов, только здесь за ним будет следовать не алгоритм, а значение нужного типа. Вот примеры определения констант базовых типов INTEGER, BOOLEAN, REAL и CHARACTER:
Zero: INTEGER is 0 Ok: BOOLEAN is True Pi: REAL is 3.1415926524 Backslash: CHARACTER is '\'
Как видно из этих примеров, имена атрибутов-констант рекомендуется начинать с заглавной буквы, за которой следуют только строчные символы.
Потомки не могут переопределять значения атрибутов-констант.
Как и другие атрибуты, класс может экспортировать константы или скрывать. Так, если C - класс, экспортирующий выше объявленные константы, а у клиента класса к сущности x присоединен объект типа C, то выражение x.Backslash обозначает символ '\'.
В отличие от атрибутов-переменных, константы не занимают в памяти места. Их введение не связано с издержками в период выполнения, а потому не страшно, если их в классе достаточно много.
Использование констант
Вот пример, показывающий, как клиент может применять константы, определенные в классе:
class FILE feature error_code: INTEGER; -- Атрибут-переменная Ok: INTEGER is 0 Open_error: INTEGER is 1 ... open (file_name: STRING) is -- Открыть файл с именем file_name -- и связать его с текущим файловым объектом do error_code := Ok ... if "Что-то не так" then error_code := Open_error end end ... Прочие компоненты ... end
Клиент может вызвать метод open и проверить успешность операции:
f: FILE; ... f.open if f.error_code = f.Open_error then "Принять меры" else ... end
Нередко нужны и наборы констант, не связанных с конкретным объектом. Их, как и раньше, можно объединить в класс, выступающий в роли родителя всех классов, которым необходимы константы. В этом случае можно не создавать экземпляр класса:
class EDITOR_CONSTANTS feature Insert: CHARACTER is 'i' Delete: CHARACTER is 'd'; -- и т.д. ... end class SOME_CLASS_FOR_THE_EDITOR inherit EDITOR_CONSTANTS ...Другие возможные родители ... feature ... ... подпрограммы класса имеют доступ к константам, описанным в EDITOR_CONSTANTS ... end
Класс, подобный EDITOR_CONSTANTS, служит лишь для размещения в нем группы констант, и его роль как "реализации АТД" (а это - наше рабочее определение класса) не столь очевидна, как в предыдущих примерах. Теоретическое обоснование введения таких классов мы обсудим позднее. Представленная схема работоспособна только при множественном наследовании, поскольку классу SOME_CLASS_FOR_THE_EDITOR могут потребоваться и другие родители.