Программирование >>  Инициализация объектов класса, структура 

1 ... 301 302 303 [ 304 ] 305 306 307 ... 395


OrQuery

NameQuery( fiery )

Наша цель - представить его в виде следующего объекта OrQuery:

NameQuery( untamed )

Однако порядок обработки такого запроса вызывает некоторые проблем:. Когда м1 определяем объект NameQuery, объект OrQuery , к которому его надо добавить, еще не определен. Поэтому необходимо место, где можно временно сохранить объект NameQuery.

Чтобы сохранить что-либо для последующего использования, традиционно применяется стек. Поместим туда наш объект NameQuery. А когда позже встретим оператор ИЛИ (объект OrQuery), то достанем NameQuery из стека и присоединим его к OrQuery в качестве левого операнда.

Объект OrQuery неполон: в нем не хватает правого операнда. До тех пор пока этот операнд не будет построен, работу с данным объектом придется прекратить.

Его можно поместить в тот же самый стек, что и NameQuery. Однако OrQuery представляет другое состояние обработки запроса: это неполный оператор. Поэтому мы определим два стека: query stack для хранения объектов, представляющих сконструированные операнды составного запроса (туда мы помещаем объект NameQuery), а второй для хранения неполных операторов с отсутствующим правым операндом. Второй стек можно трактовать как место для хранения текущей операции, подлежащей завершению, поэтому назовем его current op. Сюда мы и поместим объект OrQuery. После того как второй объект NameQuery будет определен, мы достанем объект OrQuery из стека current op и добавим к нему NameQuery в качестве правого операнда. Теперь объект OrQuery завершен и мы можем поместить его в стек query stack.

Если обработка запроса завершилась нормально, то стек current op пуст, а в стеке query stack содержится единственный объект, который и представляет весь пользовательский запрос. В нашем случае это объект класса OrQuery.

Рассмотрим несколько примеров. Первый из них - простой запрос типа NotQuery:

\~! daddy

Ниже показана трассировка его обработки. Финальным объектом в стеке query stack является объект класса NotQuery:

Помимо этих пяти членов, нам понадобятся еще два. Рассмотрим следующий запрос:

i fiery untamed



evalNot() : incomplete!

push on current op ( size == 1 ) evalWord() : daddy

pop current op : NotQuery

add operand: WordQuery : NotQuery complete!

push NotQuery on query stack

Текст, расположенный с отступом под функциями eval, показывает, как выполняется операция.

Во втором примере - составном запросе типа OrQuery - встречаются оба случая. Здесь же иллюстрируется помещение полного оператора в стек query stack:

==> fiery untamed shyly

evalWord() : fiery

push word on query stack evalOr() : incomplete!

pop query stack : fiery

add operand : WordQuery : OrQuery incomplete! push OrQuery on current op ( size == 1 ) evalWord() : untamed

pop current op : OrQuery

add operand : WordQuery : OrQuery complete! push OrQuery on query stack evalOr() : incomplete!

pop query stack : OrQuery

add operand : OrQuery : OrQuery incomplete! push OrQuery on current op ( size == 1 )

evalWord() : shyly

pop current op : OrQuery

add operand : WordQuery : OrQuery complete! push OrQuery on query stack

В последнем примере рассматривается составной запрос и применение скобок для изменения порядка вычислений:

==> fiery && ( bird untamed )

evalWord() : fiery

push word on query stack evalAnd() : incomplete!

pop query stack : fiery

add operand : WordQuery : AndQuery incomplete push AndQuery on current op ( size == 1 )

evalWord() : bird

paren is set to 1 push word on query stack evalOr() : incomplete!

pop query stack : bird

add operand : WordQuery : OrQuery incomplete! push OrQuery on current op ( size == 2 ) evalWord() : untamed

pop current op : OrQuery

add operand : WordQuery : OrQuery complete! push OrQuery on query stack evalRParen() :

paren: 0 current op.size(): 1

pop query stack : OrQuery pop current op : AndQuery add operand : OrQuery : AndQuery complete! push AndQuery on query stack

Реализация системы текстового поиска состоит из трех компонентов:



класс TextQuery, где производится обработка текста (подробно он рассматривался в разделе 16.4). Для него нет производных классов;

объектно-ориентированная иерархия Query для представления и обработки различных типов запросов;

класс UserQuery, с помощью которого представлен конечный автомат для построения иерархии Query.

До настоящего момента мы реализовали эти три компонента практически независимо друг от друга и без каких бы то ни было конфликтов. Но, к сожалению, иерархия классов Query не поддерживает требований к конструированию объектов, предъявляемых реализацией UserQuery:

классы AndQuery, OrQuery и NotQuery требуют, чтобы каждый операнд присутствовал в момент определения объекта. Однако принятая нами схема обработки подразумевает наличие неполных объектов;

наша схема предполагает отложенное добавление операнда к объектам AndQuery, OrQuery и NotQuery. Более того, такая операция должна быть виртуальной. Операнд приходится добавлять через указатель типа Query*, находящийся в стеке current op. Однако способ добавления операнда зависит от типа: для унарных (NotQuery) и бинарных (AndQuery и OrQuery) операций он различен. Наша иерархия классов Query подобные операции не поддерживает.

Оказалось, что анализ предметной области был неполон, в результате чего разработанный интерфейс не согласуется с конкретной реализацией проекта. Нельзя сказать, что анализ был неправильным, он просто неполон. Эта проблема связана с тем, что этапы анализа, проектирования и реализации отделены друг от друга и не допускают обратной связи и пересмотра. Но хотя мы не можем все продумать и все предвидеть, необходимо отличать неизбежные неправильные шаги от ошибок, обусловленных собственной невнимательностью или нехваткой времени.

В таком случае мы должны либо сами модифицировать иерархию классов Query, либо договориться, чтобы это сделали за нас. В данной ситуации мы, как авторы всей системы, сами изменим код, модифицировав конструкторы подтипов и включив виртуальную функцию-член add op() для добавления операндов после определения оператора (мы покажем, как она применяется, чуть ниже, при рассмотрении функций evalRParen() и evalWord()).

17.7.1. Определение класса UserQuery

Объект класса UserQuery можно инициализировать указателем на вектор строк, представляющий запрос пользователя, или передать ему адрес этого вектора позже, с помощью функции-члена query() . Это позволяет использовать один объект для нескольких запросов. Фактическое построение иерархии классов Query выполняется функцией eval query() :



1 ... 301 302 303 [ 304 ] 305 306 307 ... 395

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.004
При копировании материалов приветствуются ссылки.
Яндекс.Метрика