Структуры и алгоритмы обработки данных. Объектно-ориентированный подход и реализация на C++ - Кубенский А.А.
ISBN 5-94157-506-8
Скачать (прямая ссылка):


//----------------------------------------------------------------------
// Генератор порождает сообщение о готовом значении, только если // номер члена ряда равен нулю или уже готово значение // предыдущего члена суммы. Сообщение порождается только один раз.
//----------------------------------------------------------------------
Message * EMember::generate() {
// Проверка, не было ли уже порождено сообщение if (generated) return NULL;
if (number ==0) {
// Для нулевого члена суммы значение порождается сразу же generated = true;
return new SumMessage(MemberValue(0, 1));
} else if (accepted) {
// Предыдущий член суммы уже вычислен;
// вычисляем значение данного члена суммы на его основе generated = true;
return new SumMessage (MemberValue (number, pred / number) );
} else {
// Пока еще нельзя выдать значение члена суммы; return NULL;
}
}
//----------------------------------------------------------------------
// Обработчик принимает значение некоторого члена суммы и,
// если номер этого члена ровно на единицу меньше собственного // номера, запоминает его для дальнейшего вычисления.
//----------------------------------------------------------------------
bool EMember::handle(const Message & msg) {
// Проверка, не было ли уже запомнено значение предыдущего члена if (accepted) return false;
// Проверка класса сообщения
if (msg.getMs^Class () != SumMessage: imsgMemberReady) return false; const SumMessage & myMsg = (const SumMessage &)msg;
// Анализ и запоминание параметра сообщения MemberValue value = myMsg.getValue();
404
Гпава 7
if (value.getNumber() == number-1) { pred = value.getValue(); accepted = true;
}
//Во всех случаях сообщение передается дальше для анализа его // другими обработчиками (на самом деле это значение может // понадобиться разве что сумматору). return false;
}
Теперь для вызова функции суммирования нужно лишь создать фабрику для порождения новых членов суммы ряда и задать общее количество суммируемых членов:
EMemberFactory eFactory; double е = sum (eFactory, 10) ;
cout « "Approximate value for e = " « e « endl;
Приведенный выше вызов выведет в стандартный выходной поток значение:
2.71828.
Как всем хорошо известно, это значение действительно является приблизительным значением числа е.
Рекомендуется внимательно изучить программу в части порождения и обработки событий, чтобы понять, как взаимодействуют между собой различные члены суммы. На самом деле программа работает довольно медленно. Действительно, в системе циркулирует довольно много сообщений, но почти все они проходят впустую, т. к. каждое значение очередного члена суммы на самом деле необходимо только двум объектам: сумматору для добавления его к сумме и следующему члену суммы для вычисления очередного значения. Всеми остальными объектами сообщение просто игнорируется. Аналогично, все члены суммы являются потенциальными генераторами событий, однако при просмотре списка генераторов диспетчером каждый раз лишь один из членов суммы готов сгенерировать новое значение, остальные члены суммы будут ждать своей очереди.
Приведем еще несколько примеров вычисления различных сумм практически без комментариев. Работа соответствующих классов очень похожа на работу класса EMember.
Члены последовательности чисел Фибоначчи зависят друг от друга чуть более сложным образом, чем члены ряда для вычисления числа е. Каждый член последовательности Фибоначчи зависит не от одного, а от двух предыдущих членов. Сумма п первых членов последовательности чисел Фибоначчи получается, если определить класс FibMember так, как показано в листинге 7.5.
Обмен сообщениями и обработка сообщений
405
{ Листинг 7.5. Суммирование членов последовательности чисел Фибоначчи
//-------fibmember.h-----------------------------------------------------
class FibMember : public Member {
int number; // Номер члена суммы (от нуля до некоторого п)
int pred; // Запомненное значение предыдущего члена
int predPred; // Запомненное значение пред-предыдущего члена
bool acceptedl; // Предыдущее значение получено?
bool accepted2; // Пред-предыдущее значение получено?
bool generated; // Значение уже сгенерировано?
public :
// Конструктор запоминает номер FibMember(int i = 0)
: number(i), generated(false), acceptedl(false), accepted2(false)
{}
FibMember(const FibMember & src)
: number(src.number), generated(src.generated), pred(src.pred), predPred(src.predPred), acceptedl(src.acceptedl), accepted2(src.accepted2)
{}
// Реализация операций по обмену сообщениями
Message * generate();
bool handle(const Message & msg);
};
//--------------------------------------------------------------------
// Класс FibMemberFactorу описывает фабрику для создания объектов-// членов суммы последовательности первых л чисел Фибоначчи
//--------------------------------------------------------------------
class FibMemberFactory : public MemberFactory { public :
Member * createMember(int i) const { return new FibMember(i); }
};
//-------- fibmember.cpp --------------------------------------------------

