Создание объектов и выполняемых систем
6.4. Создание простых объектов
Я надеюсь, вы еще не забыли цель этой лекции — создать новую линию fancy_line с тремя станциями, как показано на рисунке в начале текста. Мы уже почти приблизились к цели, но прежде нам нужно создать объекты, представляющие остановки на линии.
Эти вспомогательные объекты будут экземплярами уже упомянутого класса STOP. Кстати, понимаете ли вы, почему нам нужен такой класс?
Время теста
Почему нам нужен класс STOP для моделирования линии метро и почему недостаточно класса STATION?
Следующий ниже рисунок дает подсказку. Остановка связана со станцией, но является другим объектом, поскольку представляет станцию, принадлежащую определенной линии.
Запрос "Какая следующая остановка?" не является методом станции (STATION) — это метод станции, принадлежащей линии (STOP). Вспомним документ требований: "Некоторые станции принадлежат двум или более линиям; они называются пересадочными". На следующем рисунке станция, следующая за станцией "Gambetta", зависит от того, на какой линии вы находитесь.
Объект STOP устроен просто. Он содержит ссылки на станцию, на линию и на следующую остановку:
Не имеет смысла иметь остановку без станции и линии. Поэтому будем требовать, чтобы station и line всегда были присоединены (не void); инвариант класса будет отражать это требование. Ссылка right может иметь значение void, чтобы указать, что данная остановка является последней на линии.
Нам нет необходимости заботиться о создании объектов STATION, поскольку они предопределены в классе TOURISM и доступны через Station_X-запросы: Station_Montrouge, Station_Issy и другие. Поэтому будем учиться созданию объектов на примере создания экземпляров класса STOP.
Первую версию класса STOP назовем SIMPLE_STOP, она имеет следующий интерфейс (доступный для просмотра в EiffelStudio):
class SIMPLE_STOP feature station: STATION — Станция, которую представляет эта остановка line: LINE -Линия, на которой находится эта остановка right: SIMPLE_STOP -Следующая остановка на той же линии. set_station_and_line (s: STATION; l: LINE) — Связать эту остановку с s и l require station_exists: s /= Void line_exists: l /= Void ensure station_set: station = s line_set: line = l link (ss: SIMPLE_STOP) -Сделать s следующей остановкой на линии. ensure right_set: right = s — Опущен инвариант: station /= Void and line /= Void; см. обсуждение end
Запрос station дает связанную с остановкой станцию, а line — линию, к которой принадлежит остановка. Запрос right дает следующую остановку. С классом связаны две команды: set_station_and_line и link. Первая позволяет передать станции одновременно станцию и линию, вторая — следующую остановку на той же линии. Такие команды, главная цель которых — установить значения ассоциированных запросов (хотя они могут делать и большее), называются получателями, или сеттерами (setters).
Рассмотрим, как создается экземпляр этого класса. Предположим, что (наряду с fancy_line: LINE) мы уже объявили:
stop1: SIMPLE_STOP
Тогда в процедуре build_a_line мы можем создать остановку:
build_a_line - Построить воображаемую линию и подсветить её на карте do Paris.display -"Создать fanc_line" Paris.put_line ( fancy_line) create stop1 -"Создать следующие остановки и закончить построение fancy_line" fancy_line.highlight end
Оставшийся псевдокод детализируется двумя частями: сначала создается линия, а затем создаются и связываются остановки линии.
Оператор create stop1 является оператором создания. Это базисная операция, создающая объекты во время выполнения программы. Ее эффект в точности соответствует смыслу слова create: создает объект и связывает его с сущностью, в данном случае stop1 присоединяется к новому объекту. На рисунках: все начинается состоянием, в котором stopI имеет значение void.
Выполнение присоединяет созданный для наших целей объект
Оператор создания create не нуждается в указании типа создаваемого объекта, так как каждая сущность, такая как stop1, объявлена с указанием типа: stop1: SIMPLE_STOP. Тип создаваемого объекта определяется типом соответствующей сущности.
Как следствие предыдущего обсуждения — все ссылочные поля нового объекта получают значение Void. Мы можем связать их с фактическими объектами, используя команды-сеттеры класса set_station_and_line и link. Давайте построим все остановки fancy_line. Мы объявим три остановки:
stop1, stop2, stop3: SIMPLE_STOP
Заметьте, синтаксис позволяет объявлять одновременно несколько сущностей одного типа. Имена сущностей разделяются запятыми, а после двоеточия указывается их тип. Числа на рисунке соответствуют порядку следования станций на нашей линии:
Это позволяет нам написать следующую версию процедуры build_a_line:
build_a_line Построить воображаемую линию и подсветить ее на карте. do Paris .display — "Создать fancy_line" Paris .put_line (fancy_line) — Создать остановки и связать каждую со своей станцией: create stop1 stop1 .set_station_and_line (Station_Montrouge, fancy_line) create stop2 stop2 .set_station_and_line ( Station_Issy, fancy_line) create stop3 stop3 .set_station_and_line (Station_Balard, fancy_line) — Связать каждую остановку со следующей за ней: stop1 .link (stop2) stop2 .link ( stop3) fancy_line .highlight end
Заметьте, как последовательно сжимается псевдокод при добавлении новых операторов - реального кода, реализующего наши намерения. В конце весь псевдокод будет удален.
Два вызова link соединяют в цепочку первую остановку со второй, а вторую — с третьей. К третьей ничего не присоединяется, ее ссылка right, получившая при создании значение void, такой и останется. Это соответствует нашим желаниям: задавать таким способом последнюю остановку на линии.
Вызовы set_station_and_line должны удовлетворять предусловию метода, требующего, чтобы аргументы были присоединены к объектам: