В.В. Кулямин - Технологии программирования. Компонентный подход (1133554), страница 26
Текст из файла (страница 26)
Выделим следующие сценарии работы или модификации программы.a. Надо сделать так, чтобы индексатор мог работать в инкрементальном режиме, читая навходе одну фразу за другой и пополняя получаемый в процессе работы индекс.b. Надо сделать так, чтобы индексатор мог игнорировать предлоги, союзы, местоимения,междометия, частицы и другие служебные слова.c. Надо сделать так, чтобы индексатор мог обрабатывать тексты, подаваемые ему на входв виде архивов.d. Надо сделать так, чтобы в индексе оставались только слова в основной грамматическойформе — существительные в единственном числе и именительном падеже, глаголы внеопределенной форме и пр.2. Определим две возможных архитектуры индексатора для сравнительного анализа.a. В качестве первой архитектуры рассмотрим разбиение индексатора на два компонента.Один компонент принимает на свой вход входной текст, полностью прочитывает его ивыдает на выходе список слов, из которых он состоит.
Второй компонент принимает навход список слов, а на выходе выдает его упорядоченный вариант без повторений. Этотвариант архитектуры построен в стиле «каналы и фильтры» (см. следующую лекцию).ВходнойтекстВыделениесловСписоксловУпорядочениесписка словИндексРисунок 29. Архитектура индексатора в стиле каналов и фильтров.b. Другой вариант архитектуры индексатора устроен следующим образом.
Имеетсявнутренняя структура данных, хранящая подготовленный на настоящий момент вариантиндекса. Он представляет собой упорядоченный список без повторений всех слов,прочитанных до настоящего момента. Кроме того, имеются две переменные — строка,хранящая последнее (быть может, не до конца) прочитанное слово, и ссылка на то словов подготовленном списке, которое лексикографически следует за последним словом(соответственно, предшествующее этому слово в списке лексикографическипредшествует последнему прочитанному слову).В дополнение к этим данным имеются следующие компоненты.i.
Первый читает очередной символ на входе и передает его на обработку одному изостальных.Если это разделитель слов (пробел, табуляция, перевод строки), управлениеполучает второй компонент.Если это буква — третий.Если входной текст кончается — четвертый.81ii.Второй компонент закачивает ввод последнего слова — оно помещается в списокперед тем местом, на которое указывает ссылка; после чего последнее словостановится пустым, а ссылка начинает указывать на первое слово в списке.iii.
Третий компонент добавляет прочитанную букву в конец последнего слова, послечего, быть может, перемещает ссылку на следующее за полученным слово всписке.iv. Четвертый компонент выдает полученный индекс на выход.Эта архитектура построена в стиле «репозиторий» (см. следующую лекцию).Обработкаразделителей словВходнойтекстЧтениеочередногосимволаОбработка буквТекущий индексОбработка концатекстаРисунок 30. Архитектура индексатора в стиле репозитория.3. Определим поддерживаемые сценарии из выделенного набора.a.
Сценарий a.Этот сценарий прямо поддерживается второй архитектурой.Чтобы поддержать его в первой, необходимо внести изменения в оба компонента так,чтобы первый компонент мог бы пополнять промежуточный список, читая входнойтекст фраза за фразой, а второй — аналогичным способом пополнять результирующийупорядоченный список, вставляя туда поступающие ему на вход слова.b.
Сценарий b.Обе архитектуры не поддерживают этот сценарий.Для его поддержки в первой архитектуре необходимо изменить первый компонент или,лучше, вставить после него дополнительный фильтр, отбрасывающий вспомогательныечасти речи.Для поддержки этого сценария второй архитектурой нужно ввести дополнительныйкомпонент, который перехватывает буквы, выдаваемые модулем их обработки(соответственно, этот модуль больше не должен перемещать указатель по итоговомусписку) и сигналы о конце слова от первого компонента, после чего он долженотсеивать служебные слова.c.
Сценарий c.Этот сценарий также требует изменений в обеих архитектурах.Однако в обоих случаях эти изменения одинаковы — достаточно добавитьдополнительный компонент, декодирующий архивы, если они подаются на вход.d. Сценарий d.Этот сценарий также не поддерживается обеими архитектурами.Требуемые им изменения аналогичны требованиям второго сценария, только в этомслучае дополнительный компонент-фильтр должен еще и преобразовывать слова в ихосновную форму и только после этого пытаться добавить результат к итоговомуиндексу.Таким образом, требуется, как и во втором случае, изменить или добавить одинкомпонент в первой архитектуре и изменить один и добавить новый во второй.4.
Мы уже выполнили оценку сценариев на предыдущем шаге. Итоги этой оценки приведеныв Таблице 6.5. Мы видели, что при использовании первого варианта архитектуры только для поддержкипервого сценария пришлось бы вносить изменения в ее компоненты. В остальных случаях82достаточно было добавить новый компонент, что несколько проще.При использовании второго варианта нам в двух разных сценариях, помимо добавлениянового компонента, потребовалось изменить компонент, обрабатывающий буквы.АрхитектураКаналы и фильтрыРепозиторийСценарий a-++++Сценарий b++*++-+*Сценарий c++*++++*Сценарий d++*++-+*Таблица 6. Итоги оценки двух вариантов архитектуры индексатора.+ обозначает возможность не изменять компонент, - — необходимость изменения компонента,* — необходимость добавления одного компонента6. В целом первая архитектура на предложенных сценариях выглядит лучше второй.Единственный ее недостаток — отсутствие возможности инкрементально поставлятьданные на вход компонентам.
Если его устранить, сделав компоненты способнымипотреблять данные постепенно, эта архитектура станет почти идеальным вариантом,поскольку она легко расширяется — для решения многих дополнительных задачпотребуется только добавлять компоненты в общий конвейер.Вторая архитектура, несмотря на выигрыш в инкрементальности, проигрывает в целом.Основная ее проблема — слишком специфически построенный компонент-обработчикбукв.
Необходимость изменить его в нескольких сценариях показывает, что нужнообъединить обработчик букв и обработчик конца слов в единый компонент, выдающийслова целиком, после чего полученная архитектура не будет ничем уступать исправленнойпервой.UML. Виды диаграмм UMLДля представления архитектуры, а точнее — различных входящих в нее структур, удобноиспользовать графические языки. На настоящий момент наиболее проработанным и наиболеешироко используемым из них является унифицированный язык моделирования (Unified ModelingLanguage, UML) [5-7], хотя достаточно часто архитектуру системы описывают просто наборомименованных прямоугольников, соединенных линиями и стрелками, которые представляютвозможные связи.UML предлагает использовать для описания архитектуры 8 видов диаграмм.
9-й вид UMLдиаграмм, диаграммы вариантов использования (см. Лекцию 4), не относится к архитектурнымпредставлениям. Кроме того, и другие виды диаграмм можно использовать для описаниявнутренней структуры компонентов или сценариев действий пользователей и прочих элементов, кархитектуре часто не относящихся. В этом курсе мы не будем разбирать диаграммы UML вдеталях, а ограничимся обзором их основных элементов, необходимым для общего пониманиясмысла того, что изображено на таких диаграммах.Диаграммы UML делятся на две группы — статические и динамические диаграммы.Статические диаграммыСтатические диаграммы представляют либо постоянно присутствующие в системе сущности исвязи между ними, либо суммарную информацию о сущностях и связях, либо сущности и связи,существующие в какой-то определенный момент времени.
Они не показывают способовповедения этих сущностей. К этому типу относятся диаграммы классов, объектов, компонентов идиаграммы развертывания.• Диаграммы классов (class diagrams) показывают классы или типы сущностей системы,характеристики классов (поля и операции) и возможные связи между ними. Примердиаграммы классов изображен на Рис. 31.Классы представляются прямоугольниками, поделенными на три части. В верхней частипоказывают имя класса, в средней — набор его полей, с именами, типами, модификаторамидоступа (public ‘+’, protected ‘#’, private ‘-’) и начальными значениями, в нижней —набор операций класса. Для каждой операции показывается ее модификатор доступа и83сигнатура.На Рис.
31 изображены классы Account, Person, Organization, Address, CreditAccount иабстрактный класс Client.Класс CreditAccount имеет private поле maximumCredit типа double, а также publicметод getCredit() и protected метод setCredit().Интерфейсы, т.е. типы, имеющие только набор операций и не определяющие способов ихреализации, часто показываются в виде небольших кружков, хотя могут изображаться и какобычные классы.
На Рис. 31 представлен интерфейс AccountInterface.Рисунок 31. Диаграмма классов.Наиболее часто используется три вида связей между классами — связи по композиции,ссылки, связи по наследованию и реализации.Композиция описывает ситуацию, в которой объекты класса A включают в себя объектыкласса B, причем последние не могут разделяться (объект класса B, являющийся частьюобъекта класса A, не может являться частью другого объекта класса A) и существуюттолько в рамках объемлющих объектов (уничтожаются при уничтожении объемлющегообъекта).Композицией на Рис. 31 является связь между классами Organization и Address.Ссылочная связь (или слабая агрегация) обозначает, что объект некоторого класса A имеетв качестве поля ссылку на объект другого (или того же самого) класса B, причем ссылки наодин и тот же объект класса B могут иметься в нескольких объектах класса A.И композиция, и ссылочная связь изображаются стрелками, ведущими от класса A к классуB.
Композиция дополнительно имеет закрашенный ромбик у начала этой стрелки.Двусторонние ссылочные связи, обозначающие, что объекты могут иметь ссылки друг надруга, показываются линиями без стрелок. Такая связь показана на Рис. 31 между классамиAccount и Client.Эти связи могут иметь описание множественности, показывающее, сколько объектовкласса B может быть связано с одним объектом класса A.
Оно изображается в видетекстовой метки около конца стрелки, содержащей точное число или нижние и верхниеграницы, причем бесконечность изображается звездочкой или буквой n. Для двусторонних84•связей множественности могут показываться с обеих сторон. На Рис. 31 множественности,изображенные для связи между классами Account и Client, обозначают, что один клиентможет иметь много счетов, а может и не иметь ни одного, и счет всегда привязан ровно кодному клиенту.Наследование классов изображается стрелкой с пустым наконечником, ведущей отнаследника к предку. На Рис. 31 класс CreditAccount наследует классу Account, а классыPerson и Organization — классу Client.Реализация интерфейсов показывается в виде пунктирной стрелки с пустым наконечником,ведущей от класса к реализуемому им интерфейсу, если тот показан в видепрямоугольника.