Студопедия
Главная страница | Контакты | Случайная страница

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

Проектирование редактора документов

Читайте также:
  1. I. ДОКУМЕНТАЛИСТИКА, ДОКУМЕНТОВЕДЕНИЕ
  2. IV. Состав необходимых для государственного учета документов
  3. Oт редактора перевода
  4. V. Порядок представления заявителями документов для осуществления государственного учета
  5. VI. Правила оформления и предоставления пакета конкурсных документов
  6. X. ПРОЕКТИРОВАНИЕ НОВЫХ ГОРОДОВ
  7. А описания документов?
  8. АРХИВНЫЕ МАТЕРИАЛЫ (Масонские коллекции и собрания документов) орргб.
  9. Аудит учредительных документов.
  10. Бланки документов изготавливают

 

virtual void CheckCharacter(Character*); virtual void CheckRow(Row*); virtual void Checklmage(Image*);

//... и так далее List<char*>& GetMisspellings();

protected:

virtual bool IsMisspelled(const char*);

private:

char _currentWord[MAX_WORD_SIZE]; List<char*> _misspellings;

Операция проверки в классе SpellingChecker для глифов типа Character могла бы выглядеть так:

void SpellingChecker::CheckCharacter (Character* с) { const char ch = c->GetCharCode();

if (isalpha(ch)) {

// добавить букву к _currentWord

} else {

// встретилась не-буква

if (IsMisspelled(_currentWord)) {

// добавить _currentWord в „misspellings _misspellings.Append(strdup(_currentWord));

_currentWord[0] = '\б';

// переустановить _currentWord для проверки // следующего слова

I I

Обратите внимание, что мы определили специальную операцию Get Char Code только для класса Character. Объект проверки правописания может работать со специфическими для подклассов операциями, не прибегая к проверке или приве-дению типов, а это позволяет нам трактовать некоторые объекты специальным образом.

Объект класса CheckCharacter накапливает буквы в буфере _current Word. Когда встречается не-буква, например символ подчеркивания, этот объект вызы­вает операцию IsMisspelled для проверки орфографии слова, находящегося


 

Правописание и расстановка переносов

в _currentWord.1 Если слово написано неправильно, то CheckCharacter добав­ляет его в список слов с ошибками. Затем буфер _currentWord очищается для приема следующего слова. По завершении обхода можно добраться до списка слов с ошибками с помощью операции GetMis spell ings.

Теперь логично обойти всю структуру глифов, вызывая CheckMe для каждого глифа и передавая ей объект проверки правописания в качестве аргумента. Тем самым текущий глиф для Spell ingChecker идентифицируется и может продол­жать проверку:

SpelIingChecker spel1ingChecker; Composition* с;

Glyph* g; Preorderlterator i(c);

for (i.First ();!i.IsDone(); i.NextO) {

д = i.CurrentItern();

g->CheckMe(spellingChecker); }

На следующей диаграмме показано, как взаимодействуют глифы типа Character и объект SpellingChecker.

Этот подход работает при поиске орфографических ошибок, но как он может помочь в поддержке нескольких видов анализа? Похоже, что придется добавлять операцию вроде CheckMe (SpellingChecker&) в класс Glyph и его подклассы

1 Функция IsMisspel led реализует алгоритм проверки орфографии, детали которого мы здесь не приводим, поскольку мы сделали его независимым от дизайна Lexi. Мы можем поддержать разные алгоритмы, порождая подклассы класса SpellingChecker. Или применить для этой цели паттерн стратегия (как для форматирования в разделе 2.3).


Проектирование редактора документов

 

всякий раз, как вводится новый вид анализа. Так оно и есть, если мы настаиваем на независимом классе для каждого вида анализа. Но почему бы не придать всем видам анализа одинаковый интерфейс? Это позволит нам использовать их поли­морфно. И тогда мы сможем заменить специфические для конкретного вида ана­лиза операции вроде CheckMe (SpellingCheckerk) одной инвариантной опера­цией, принимающей более общий параметр.

Класс Visitor и его подклассы

Мы будем использовать термин «посетитель» для обозначения класса объек­тов, «посещающих» другие объекты во время обхода, дабы сделать то, что необхо­димо в данном контексте.1 Тогда мы можем определить класс Visitor, описыва­ющий абстрактный интерфейс для посещения глифов в структуре:

class Visitor { public:

virtual void VisitCharacter(Character*) { }

virtual void VisitRow(Row*) { }

virtual void Visitlmage(Image*) { }

... и так далее

Конкретные подклассы Vi s it o r выполняют разные виды анализа. Например, можно было определить подкласс SpellingCheckingVisitor для проверки правописания и подкласс Hyphenat ionVisitor для расстановки переносов. При этом SpellingCheckingVisitor был бы реализован точно так же, как мы реа­лизовали класс SpellingChecker выше, только имена операций отражали бы более общий интерфейс класса Visitor. Так, операция CheckCharacter назы­валась бы VisitCharacter.

Поскольку имя CheckMe не подходит для посетителей, которые ничего не проверяют, мы использовали бы имя Accept. Аргумент этой операции тоже при­шлось бы изменить на Visi tor&, чтобы отразить тот факт, что может принимать­ся любой посетитель. Теперь для добавления нового вида анализа нужно лишь определить новый подкласс класса Visitor, а трогать классы глифов вовсе не обязательно. Мы поддержали все возможные в будущем виды анализа, добавив лишь одну операцию в класс Glyph и его подклассы.

О выполнении проверки правописания говорилось выше. Такой же подход бу­дет применен для аккумулирования текста в подклассе Hyphenat ionVisitor. Но после того как операция VisitCharacter из подкласса Hyphenat ionVisitor закончила распознавание целого слова, она ведет себя по-другому. Вместо провер­ки орфографии применяется алгоритм расстановки переносов, чтобы определить, в каких местах можно перенести слово на другую строку (если это вообще возмож­но). Затем для каждой из найденных точек в структуру вставляется разделяющий

«Посетить» - это лишь немногим более общее слово, чем «проанализировать». Оно просто предвос­хищает ту терминологию, которой мы будем пользоваться при обсуждении следующего паттерна.


Правописание и расстановка переносов

(discretionary) глиф. Разделяющие глифы являются экземплярами подкласса Glyph - класса Discretionary.

Разделяющий глиф может выглядеть по-разному в зависимости от того, явля­ется он последним символом в строке или нет. Если это последний символ, глиф выглядит как дефис, в противном случае не отображается вообще. Разделяющий глиф запрашивает у своего родителя (объекта Row), является ли он последним потомком, и делает это всякий раз, когда от него требуют отобразить себя или вычислить свои размеры. Стратегия форматирования трактует разделяющие гли­фы точно так же, как пропуски, считая их «кандидатами» на завершающий сим­вол строки. На диаграмме ниже показано, как может выглядеть встроенный раз­делитель.

Паттерн посетитель

Вышеописанная процедура - пример применения паттерна посетитель. Его главными участниками являются класс Visitor и его подклассы. Паттерн посе­титель абстрагирует метод, позволяющий иметь заранее неопределенное число видов анализа структур глифов без изменения самих классов глифов. Еще одна полезная особенность посетителей состоит в том, что их можно применять не только к таким агрегатам, как наши структуры глифов, но и к любым структурам, состоящим из объектов. Сюда входят множества, списки и даже направленные ациклические графы. Более того, классы, которые обходит посетитель, необяза­тельно должны быть связаны друг с другом через общий родительский класс. А это значит, что посетители могут пересекать границы иерархий классов.

Важный вопрос, который надо задать себе перед применением паттерна посе­титель, звучит так: «Какие иерархии классов наиболее часто будут изменяться?» Этот паттерн особенно удобен, если необходимо выполнять действия над объек­тами, принадлежащими классу со стабильной структурой. Добавление нового вида посетителя не требует изменять структуру класса, что особенно важно, когда класс большой. Но при каждом добавлении нового подкласса вы будете вынужде­ны обновить все интерфейсы посетителя с целью включить операцию Visit... для этого подкласса. В нашем примере это означает, что добавление подкласса Foo класса Glyph потребует изменить класс Visitor и все его подклассы, чтобы до­бавить операцию Visit Foo. Однако при наших проектных условиях гораздо бо­лее вероятно добавление к Lexi нового вида анализа, а не нового вида глифов. Поэтому для наших целей паттерн посетитель вполне подходит.


Проектирование редактора документов

Резюме

При проектировании Lexi мы применили восемь различных паттернов:

а компоновщик для представления физической структуры документа;

а стратегия для возможности использования различных алгоритмов форма­тирования;

а декоратор для оформления пользовательского интерфейса;

а абстрактная фабрика для поддержки нескольких стандартов внешнего об­лика;

а мост для поддержки нескольких оконных систем;

а команда для реализации отмены и повтора операций пользователя;

а итератор для обхода структур объектов;

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

Ни одно из этих проектных решений не ограничено документо-ориентиро-ванными редакторами вроде Lexi. На самом деле в большинстве нетривиальных приложений есть возможность воспользоваться многими из этих паттернов, быть может, для разных целей. В приложении для финансового анализа паттерн компоновщик можно было бы применить для определения инвестиционных портфелей, разбитых на субпортфели и счета разных видов. Компилятор мог бы использовать паттерн стратегия, чтобы поддержать реализацию разных схем распределения машинных регистров для целевых компьютеров с различной архи­тектурой. Приложения с графическим интерфейсом пользователя вполне могли бы применить паттерны декоратор и команда точно так же, как это сделали мы.

Хотя мы и рассмотрели несколько крупных проблем проектирования Lexi, но осталось гораздо больше таких, которых мы не касались. Но ведь и в книге описа­ны не только рассмотренные восемь паттернов. Поэтому, изучая остальные пат­терны, подумайте о том, как вы могли бы применить их к Lexi. А еще лучше поду­майте об их использовании в своих собственных проектах!


 




Дата добавления: 2015-09-11; просмотров: 80 | Поможем написать вашу работу | Нарушение авторских прав

Обязанность Операции | Оформление пользовательского интерфейса | Оформление пользовательского интерфейса | Поддержка нескольких стандартов внешнего облика | Поддержка нескольких оконных систем | Проектирование редактора документов | Подклассы Windowlmp | Операции пользователя | Операции пользователя | Правописание и расстановка переносов |


lektsii.net - Лекции.Нет - 2014-2025 год. (0.008 сек.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав