(При первом чтении этот раздел можно опустить или ограничиться его беглым просмотром.)
Простые, но не защищенные модули могут быть не достаточно устойчивыми для использования их у произвольных клиентов. В таких случаях возникает необходимость создания нескольких классов, играющих роль фильтров. В отличие от ранее рассмотренных фильтров, устанавливаемых между внешним миром и обрабатывающими модулями, новые фильтры будут устанавливаться между "беспечными" клиентами с одной стороны и незащищенными классами с другой стороны.
Хотя было показано, что обычно это не лучший подход к проектированию, полезно рассмотреть, как выглядят классы, если использовать толерантный стиль в некоторых особых случаях. Класс STACK3, представленный ниже, иллюстрирует эту идею.
Поскольку классу понадобятся целочисленные коды ошибок, удобно для этой цели использовать ранее не введенную нотацию "unique" для целочисленных констант. Если объявить множество атрибутов следующим образом:
a, b, c, ...: INTEGER is unique
то в результате этого объявления a, b, c получат последовательно идущие целочисленные значения. Эти значения будут даваться компилятором с гарантией того, что все объявленные таким образом константы получат различные значения (будут уникальными). По принятому соглашению, всем объявляемым таким образом константам даются имена, начинающиеся с буквы в верхнем регистре и с остальными символами в нижнем регистре, например Underflow.
Вот написанная в этом стиле толерантная версия нашего класса стек. Заметьте, что этот текст, возможно пропущенный при первом чтении, включен только для понимания толерантного стиля. Он не является примером рекомендуемого стиля проектирования по причинам, обсуждаемым ниже, но которые достаточно ясны при просмотре этого текста.
indexing description: "Стеки: Структуры с политикой доступа Last-In, First-Out % %Первый пришел - Последний ушел, с фиксированной емкостью; % %толерантная версия, устанавливающая код ошибки в случае % %недопустимых операций." class STACK3 [G] creation make feature - Initialization (Инициализация) make (n: INTEGER) is -- Создать стек, содержащий максимум n элементов, если n > 0; -- в противном случае установить код ошибки равным Negative_size. -- Без всяких предусловий! do if capacity >= 0 then capacity := n create representation.make (capacity) else error := Negative_size end ensure error_code_if_impossible: (n < 0) = (error = Negative_size) no_error_if_possible: (n >= 0) = (error = 0) capacity_set_if_no_error: (error = 0) implies (capacity = n) allocated_if_no_error: (error = 0) implies (representation /= Void) end feature - Access (Доступ) item: G is -- Элемент вершины, если существует; в противном случае -- значение типа по умолчанию. -- с ошибкой категории Underflow. -- Без всяких предусловий! do if not empty then check representation /= Void end Result := representation.item error := 0 else error := Underflow -- В этом случае результатом является значение по умолчанию end ensure error_code_if_impossible: (old empty) = (error = Underflow) no_error_if_possible: (not (old empty)) = (error = 0) end feature -- Status report (Отчет о статусе) empty: BOOLEAN is -- Пуст ли стек? do Result := (capacity = 0) or else representation.empty end error: INTEGER -- Индикатор ошибки, устанавливаемый различными компонентами -- в ненулевое значение, если они не могут выполнить свою работу full: BOOLEAN is -- Заполнен ли стек? do Result := (capacity = 0) or else representation.full end Overflow, Underflow, Negative_size: INTEGER is unique -- Возможные коды ошибок feature -- Element change (Изменение элементов) put (x: G) is -- Добавить x на вершину, если возможно; иначе задать код ошибки. -- Без всяких предусловий! do if full then error := Overflow else check representation /= Void end representation.put (x); error := 0 end ensure error_code_if_impossible: (old full) = (error = Overflow) no_error_if_possible: (not old full) = (error = 0) not_empty_if_no_error: (error = 0) implies not empty added_to_top_if_no_error: (error = 0) implies item = x one_more_item_if_no_error: (error = 0) implies count = old count + 1 end remove is -- Удалить вершину, если возможно; иначе задать код ошибки. -- Без всяких предусловий! do if empty then error := Underflow else check representation /= Void end representation.remove error := 0 end ensure error_code_if_impossible: (old empty) = (error = Underflow) no_error_if_possible: (not old empty) = (error = 0) not_full_if_no_error: (error = 0) implies not full one_fewer_item_if_no_error: (error = 0) implies count = old count - 1 end feature {NONE} - Implementation (Реализация) representation: STACK2 [G] -- Незащищенный стек используется для реализации capacity: INTEGER -- Максимальное число элементов стека end - class STACK3
Толерантный подход остается полезным для модулей, принимающих данные от внешнего мира. Как отмечалось, в этом случае строятся фильтры, отделяющие внешний мир от обрабатывающих модулей. Класс STACK3 иллюстрирует идеи построения подобных фильтров. |