Основы объектно-ориентированного проектирования

         

Введение состояния


К счастью, есть выход. Для его нахождения следует обратиться, как и положено, к абстрактному типу данных.

До сих пор список рассматривался как пассивное хранилище информации. Для обеспечения клиентов лучшим сервисом, список должен стать активным, "запоминая" точку выполнения последней операции.

Как отмечалось в этой лекции, без колебаний можно рассматривать объекты как машины с внутренним состоянием и вводить как команды, изменяющие состояние, так и запросы на этом состоянии. В первом решении список уже имел состояние, определяемое его содержимым и модифицируемое командами, такими как put and remove; но, добавив еще несколько компонентов, мы получим лучший интерфейс, делающий класс более простым и эффективным.

Помимо содержимого списка состояние теперь будет включать текущую активную позицию или курсор, интерфейс теперь будет позволять явным образом передвигать курсор.


Рис. 5.7.  Список с курсором

Мы полагаем, что курсор может указывать на элемент списка, если таковые имеются, или быть в позиции слева от первого - в этом случае булев запрос before будет возвращать true, или справа от последнего - тогда after принимает значение true.

Примером команды, передвигающей курсор, является процедура search, заменяющая функцию occurrence. Вызов l.search(v) передвинет курсор к первому элементу со значением v справа от текущей позиции курсора, или передвинет его в позицию after, если таких элементов нет. Заметьте, помимо прочего, это решает проблему множественных вхождений, - просто повторяйте поиск столько раз подряд, сколь это необходимо. Для симметрии можно также иметь search_back.

Основные команды манипулирования курсором:

  • start и finish, передвигающие курсор в первую и последнюю позицию, если они определены;
  • forth и back, передвигающие курсор в следующую и предыдущую позицию;
  • go(i), передвигающие курсор в позицию i.

Кроме before и after запросы о позиции курсора включают index, целочисленный номер позиции, начинающийся с 1 для первой позиции, а также булевы запросы is_first и is_last.


Процедуры построения и модификации списка - вставка, удаление, замена - становятся проще, поскольку они не должны заботиться о позиции, а будут действовать на элемент, заданный курсором. Все циклы исчезают! Например, remove не будет теперь вызываться как l.remove (i), а просто l.remove. Необходимо установить точные и согласованные условия того, что случится с курсором при выполнении каждой операции:
  • Remove, без аргументов, удаляет элемент в позиции курсора и перемещает курсор к правому соседу, так что значение index не изменится в результате.
  • Put_right (v: G) вставляет элемент со значением v справа от курсора, не передвигая его, так что значение index не изменится.
  • Put_left (v: G) вставляет элемент со значением v слева от курсора, не передвигая его, увеличивая значение index на единицу.
  • Replace (v: G) изменяет значение элемента в позиции курсора. Значение этого элемента может быть получено функцией item, не имеющей аргументов, которая может быть реализована атрибутом.


Содержание раздела