Как происходит отслеживание свободного экстента? |
Создание объектов и выполняемых систем
6.5. Процедуры создания
Процедура build_a_line использует простейшую форму создания:
create stop;Листинг 6.1.
Этот оператор выполняет свою работу для сущности stop типа SIMPLE_STOP. Но можно его улучшить. Как показывает последняя версия процедуры, типичная схема создания остановки связывает ее с уже существующей станцией
create stop stop.set_station_and_line (existing_station, existing_line)Листинг 6.2.
Такой подход требует вызова метода непосредственно после вызова оператора создания, чтобы связать новый объект со станцией и линией. Объект, полученный в результате создания, как отмечалось, не имеет смысла, если он не связан со станцией и линией. Нам хотелось бы выразить это в виде инварианта:
invariant station_exists: station /= Void line_exists: line /= Void
При таком подходе класс становится некорректным, поскольку инвариант класса должен выполняться сразу же после создания, а этого не произойдет после простого выполнения create в пример 6.1.
Так появляются два повода слить два оператора в один — оператор создания и вызов set_station_and_line.
- Первый довод — удобство. Любой клиент, нуждающийся в создании остановки, обязан выполнить две команды. Если он забудет вторую, ограничившись только созданием объекта, то результатом будет некорректное поведение ПО и отказ при выполнении. Общее правило проектирования ПО заключается в том, что следует избегать создания элементов, требующих специальных предписаний: "Когда вы сказали А, то не забудьте после этого сказать Б" (программисты, как и обычные люди, не всегда читают инструкции и неукоснительно следуют им). Лучше обеспечить операцию, избавляющую от необходимости изучения хитроумного интерфейса.
- Второй довод — корректность. Мы хотим верить, что экземпляры класса непосредственно с момента создания являются согласованными, в данном случае имеют станцию и линию.
Для удовлетворения этих концепций мы можем объявлять в классе одну или несколько процедур создания. Процедурой создания является команда, которую клиент должен вызвать всякий раз, когда он создает экземпляр класса, убедившись при этом, что экземпляр класса должным образом инициализирован, удовлетворяя, в частности, всем инвариантам класса.
Введем процедуру создания, set_station_and_line, и объявим теперь наши остановки как
stop1, stop2, stop3: STOP
Вместо класса SIMPLE_STOP теперь используется класс STOP, в котором объявлена процедура создания, заменяющая прежнюю процедуру create пример 6.1. Теперь вместо двух операторов, как в пример 6.2, можно просто вызывать процедуру создания:
create stop1.set_station_and_line(Station_Montrouge, fancy_line)Листинг 6.3.
Единственная разница между STOP и его предшественником: STOP имеет желаемый инвариант station /= Void и объявляет метод set_station_and_line как процедуру создания. Вот как выглядит теперь интерфейс класса, в котором изменилось немногое:
В верхних строчках интерфейса класса появилось новое предложение:
create set_station_and_line
Здесь использовано знакомое ключевое слово create, а далее перечисляется одна из команд класса, set_station_and_line. Это предложение говорит клиенту-программисту, что класс рассматривает set_station_and_line как процедуру создания. В предложении create указана единственная процедура создания, но разрешается вообще не задавать процедур создания или задать несколько таких процедур, поскольку могут существовать различные способы инициализации вновь созданного объекта.
Следствием включения такого предложения в интерфейс класса является то, что клиент не может теперь при создании объекта задействовать базисную форму create stop пример 6.1. Ему необходимо использовать одну из специальных процедур создания в форме пример 6.3.
Это правило позволяет автору класса заставить клиента выполнить подходящую инициализацию всех создаваемых экземпляров класса. Оно тесно связано с инвариантами и требованием, чтобы непосредственно после создания объект удовлетворял всем условиям, налагаемыми инвариантами класса. В нашем примере инвариантами являются:
station_exists: station /= Void line_exists: line /= Void
Предусловие set_station_and_line, в свою очередь, требует выполнения этих условий. Это общий принцип.