Гради Буч - Объектно-ориентированный анализ и проектирование с примерами приложений на С++ (1158635), страница 83
Текст из файла (страница 83)
Конкретный источник знаний, со своей стороны, можетпроявлять интерес к одному или нескольким таким объектам (зависеть от них)и поэтому фраза, слово и символ шифра должны поддерживать связь систочником знаний, чтобы при появлении предположения относительнообъекта уведомлялись соответствующие источники знаний. Это напоминаетмеханизм зависимостей языка Smalltalk, упомянутый в главе 4. Дляреализации этого механизма введем следующий класс-примесь:class Dependent {public:Dependent();Dependent(const Dependent&);virtual ~Dependent();...protectedUnboundedCollection<KnowledgeSource*> references;};Мы забежали несколько вперед и намекнули на возможнуюреализацию класса, чтобы показать связь с библиотекой фундаментальныхклассов, описанной в главе 9.
В классе определен один внутренний элемент коллекция указателей на источники знаний. 39Определим для этого класса следующие операции:•addДобавить ссылку на источник знанийУдалить ссылку на источник знаний•removeВозвратить число зависящих объектов•numberOfDependentsИзвестить каждого зависимого•notifyПоследняя операция является пассивным итератором: при ее вызовепередается как параметр действие, которое надо выполнить над всемизависящими объектами в коллекции.Зависимость может примешиваться к другим классам. Например,буква шифра - это объект информационной доски, от которого зависят другие,так что мы можем скомбинировать две этих абстракции для получениянужного поведения.
Такое применение примесей поощряет повторноеиспользование и разделение понятий в нашей архитектуре.Символы шифра и алфавиты имеют еще одно общее свойство:относительно объектов этих классов могут делаться предположения.Вспомните, что предположение (Assumption) является одним из объектов надоске (BlackboardObject). Так, некоторый источник знаний можетдопустить, что буква K в шифре соответствует букве Р исходного текста.
Помере решения задачи может абсолютно точно выясниться, что G означает J.Поэтому введен еще один класс:class Affirmation . . .Этот класс отвечает за высказывания (предположения илиутверждения) относительно связанного с ним объекта. Мы используем этоткласс не как примесь, а для агрегации. Буква, например, не являетсяпредположением, но может иметь предположение о себе.В нашей системе предположения допускаются только в отношенииотдельных букв и алфавитов. Можно, например, предположить, что какаялибо буква шифра соответствует некоторой букве алфавита.
Алфавит состоитиз набора букв, относительно которых делаются предположения. ОпределяяAffirmation как независимый класс, мы выражаем в нем сходное поведениеэтих двух классов, несвязанных наследованием.Определим следующий набор операций для экземпляров этого класса:Сделать высказывание•makeОтменить высказывание•retractВернуть шифрованный эквивалент для заданной•chiphertextбуквы исходного текстаВернуть исходный текстовый эквивалент для•plaintextзаданной буквы шифраИз предыдущего обсуждения видно, что надо ясно различать две роливысказываний: временные предположения о соответствиях между буквамишифра и текста и окончательно доказанные соответствия - утверждена. Помере расшифровки криптограммы может делаться множество различныхпредположений о соответствии букв шифра и текста, но в конце концовнаходятся окончательные соответствия для всего алфавита.
Чтобы отразитьэти роли, уточним ранее выявленный класс Assumption в подклассеAssertion (утверждение). Экземпляры обоих классов управляютсяобъектами класса Affirmation и могут помещаться на доску. Дляподдержки введенных ранее операций make и retract нам необходимоопределить следующие селекторы:•isPlainLetterAssertedопределена ли эта буква текстадостоверно?определена ли эта буква шифра•isCipherLetterAssertedдостоверно?•plainLetterHasAssumptlonесть ли предположение об этойбукве текста?есть ли предположение об этой•cipherLetterHasAssumptionбукве шифра?Теперь мы можем определить класс Assumption.
Поскольку даннаяабстракция носит исключительно структурный характер, се состояние можносделать открытым:class Assumption : public BlackboardObject {public:…BlackboardObject* target;KnowledgeSource* creator;String<char> reason;char plainLetter;char chipherLetter;};Отметим, что мы повторно использовали еще один класс среды,описанной в главе 9, а именно, параметризуемый класс String.Класс Assumption является объектом информационной доски,поскольку информация о сделанных предположениях используется всемиисточниками знаний. Отдельные члены класса выражают следующие егосвойства:•targetОбъект доски, о котором делаетсяпредположениеИсточник знаний, который сделал•creatorпредположениеОснование для сделанного предположения•reasonПредполагаемое значение буквы исходного•cipherLetterтекстаНеобходимость каждого из перечисленных свойств в значительнойстепени объясняется природой предположений: источник знании формируетпредполагаемое соответствие "буква исходного текста - буква шифра" наосновании каких-то причин (обычно, некоторого правила).
Назначениепервого свойства target менее очевидно. Оно нужно для отката. Еслисделанное предположение не подтвердится, то нужно восстановить состояниеобъектов на доске, которые воспользовались предположением, а они должныизвестить источники знаний, что их смысл изменился.Далее определим подкласс Assertion:class Assertion : public Assumption ...Общим для классов Assumption и Assertion является следующийселектор:•isRetractaole Является ли соответствие потенциальноневерным?Для всех высказанных предположений значение предикатаisRetractable является истинным, а для утверждений - ложным.
Сделанноеутверждение уже нельзя ни изменить ни отвергнуть.Рис. 11-2. Классы зависимостей и высказыванийНа рис. 11-2 приведена диаграмма, поясняющая связь классовзависимостей и высказываний. Обратите особое внимание на роли, которыеиграют упомянутые абстракции в различных ассоциациях. Например, классKnowledgeSource в одном аспекте является создателем (creator)предположения, а в другом - ссылается (referencer) на букву шифра.
Изразличия ролей естественным образом вытекают различия протоколоввзаимодействия.Проектирование объектов информационной доски. Завершимпроектирование, добавив кроме класса алфавита классы для предложения(Sentence), слова (Word) и буквы шифра (cipherLetter). Предложениепредставляет собой просто объект доски (от которого зависят другиеобъекты), содержащий список слов, Исходя из этого, запишем:class Sentence : public BlackboardObject,virtual public Dependent {public:…protected:List<Word*>. words;};Суперкласс Dependent определен виртуальным, поскольку мыожидаем, что будут подклассы от sentence, которые захотят наследоватьтакже и от Dependent.
При этом для всех таких подклассов члены классаDependent будут общими.В дополнение к операциям register и resign (определенным всуперклассе BlackboardObject) и четырем операциям, унаследованным откласса Dependent, мы добавляем еще две специфические операции дляпредложения:Текущее значение предложения.•valueИстинно, если о всех словах в предложении•isSolvedсделаны утверждения.Первоначальное значение value совпадает с текстом криптограммы.Когда isSolved станет истиной, value вернет исходный расшифрованныйтекст.Слово является объектом доски и источником зависимости. Оносостоит из букв. Для удобства источников знаний в класс слова введеныуказатели на все предложение, а также на предыдущее и следующее слова впредложении. Описание класса Word выглядит так:class Word : public BlackboardObject,virtual public Dependent {public:…Sentence& sentence() const;Word* previous 0 const;Word* next() const;protected:List<CipherLetter*> letters;};Так же как для предложения, в класс слова введены дведополнительные операции:•valueТекущее значение слова.Истинно, если о всех буквах слова сделаны•isSolvedутверждения.Теперь можно определить класс cipherLetter (буква шифра).
Буквышифра являются объектами информационной доски и порождаютзависимости. Кроме того, они имеют значение (буква, как она записывается вшифровке, например, н) и коллекцию возможных предположений иутверждений о соотнесении ее с буквами исходного текста. Для организацииколлекции мы используем класс Affirmation.
Опишем класс буквыследующим образом:class CipherLetter : public BlackboardObject,virtual public Dependent {public:…char value() const;int isSolvedO const; ...protected:char letter;Affirmation affirmations;};Отметим, что и в этот класс добавлена та же пара селекторов поаналогии с классами слова и предложения.
Для клиентов этого объекта нужнопредусмотреть защищенные операции доступа к предположениям иутверждениям.Объект affirmations, включенный в этот класс, содержит коллекциюпредположений и утверждений в порядке их выдвижения. Последний элементколлекции содержит текущее предположение или утверждение. Смыслхранения последовательности решения задачи состоит в возможностиобучения источников знании на собственных ошибках. Поэтому в классAffirmation введены два дополнительных селектора:возвращает последнее предположение или•moatRecentутверждениевозвращает n-ое высказывание (предположение•statementAtили утверждение)Уточнив поведение класса, мы можем принять правильные решения оего реализации.