Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лабораторные работы Case-средства СУ

.pdf
Скачиваний:
43
Добавлен:
11.02.2015
Размер:
1.16 Mб
Скачать

Лабораторная работа №3. Использование паттерна Наблюдатель

Цель занятия: познакомится с принципом использования паттерна Наблюдатель при выборе архитектуры ПО и последующей реализации

Порядок выполнения работы:

1.Ознакомится с примером задания и разработанным кодом

2.Выполнить общую часть лабораторной работы

3.Выполнить индивидуальную часть лабораторной работы

Наблюдатель (англ. Observer) — поведенческий шаблон проектирования. Также известен как «подчинённые» (Dependents), «издатель-подписчик» (Publisher-Subscriber).

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

Назначение

Определяет зависимость типа «один ко многим» между объектами таким образом,

что при изменении состояния одного объекта все зависящие от него оповещаются об этом событии.

Область применения

Шаблон «наблюдатель» применяется в тех случаях, когда система обладает следующими свойствами:

существует, как минимум, один объект, рассылающий сообщения;

имеется не менее одного получателя сообщений, причём их количество и состав могут изменяться во время работы приложения;

нет надобности очень сильно связывать взаимодействующие объекты, что полезно для повторного использования.

Данный шаблон часто применяют в ситуациях, в которых отправителя сообщений не интересует, что делают получатели с предоставленной им информацией.

Реализация

21

При реализации шаблона «наблюдатель» обычно используются следующие классы:

Observable — интерфейс, определяющий методы для добавления, удаления и оповещения наблюдателей;

Observer — интерфейс, с помощью которого наблюдатель получает оповещение;

ConcreteObservable — конкретный класс, который реализует интерфейс

Observable;

ConcreteObserver — конкретный класс, который реализует интерфейс

Observer.

Общая часть лабораторной работы

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

Теоретические обоснования и идеи заложенные в основу этой диаграммы также были рассмотрены. Задача: по имеющейся диаграмме классов написать программный код,

используя паттерн Наблюдатель.

Описание задачи: Метеостанция отслеживает погодные условия. Приложение должно отображать 3 визуальных элемента: текущую погоду (температуру, влажность,

давление), накопленную статистику по погоде и предсказание погоды. Все данные обновляются в реальном времени, по мере того, как метеостанция получает данные с датчиков. Также необходимо предусмотреть возможность в будущем добавлять 4, 5 и т.п.

визуальные элементы.

22

1. Создаем новый пустой проект в Visual Studio и выбираем соответствующие настройки:

2. Создаем интерфейс Observers, от которого затем будем наследовать всех Наблюдателей. У интерфейса есть только заголовочный файл. Метод update() является чистым

23

виртуальным, для реализации динамического полиморфизма. Метод update() предназначен для обновления данных у Наблюдателей.

#pragma once

class Observer

{

public:

virtual void update(float, float, float)=0;

};

3. Создаем интерфейс DisplayElement, от которого затем будем наследовать всех Наблюдателей. У интерфейса есть только заголовочный файл. Метод display() является чистым виртуальным, для реализации динамического полиморфизма. Метод display()

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

#pragma once

class DisplayElement

{

virtual void display()=0;

};

4. Реализуем Наблюдателя, например Наблюдателя содержащего и отображающего текущие погодные условия. Обратите внимание на наследование от 2-х интерфейсов! В

классе Наблюдателя находится реализация методов update() и display(). Заводятся переменные, описывающие значения влажности, температуры и давления.

Заголовочный файл:

#pragma once

#include "Observer.h" #include "DisplayElement.h" class CurrentDisplay :

public Observer, public DisplayElement

{

float temperature, humidity, pressure;

public: CurrentDisplay(void); ~CurrentDisplay(void);

void update(float temperature, float humidity, float pressure); void display();

};

Файл реализации:

#include <iostream> using namespace std;

#include "CurrentDisplay.h"

24

CurrentDisplay::CurrentDisplay(void)

{

temperature=0;

humidity=0;

pressure=0;

}

CurrentDisplay::~CurrentDisplay(void)

{

}

void CurrentDisplay::update(float temperature, float humidity, float pressure)

{

this->temperature=temperature; this->pressure=pressure; this->humidity=humidity;

}

void CurrentDisplay::display()

{

cout << "Current Temperature " << temperature << endl; cout << "Current Humidity " << humidity << endl;

cout << "Current Pressure " << pressure << endl;

}

5. Реализуем Наблюдателя отображающего статистическую информацию, по последним

10 значениям.

Заголовочный файл:

#pragma once #include <iostream>

#include "observer.h" #include "DisplayElement.h" class StatisticsDisplay :

public Observer, public DisplayElement

{float average_temperature, average_humidity, average_pressure; float array_temperature[10];

float array_humidity[10]; float array_pressure[10]; public:

StatisticsDisplay(void); ~StatisticsDisplay(void);

void update(float temperature, float humidity, float pressure); void display();

};

Файл реализации:

#include "StatisticsDisplay.h" using namespace std;

StatisticsDisplay::StatisticsDisplay(void)

{

for(int i=0; i<10; i++)

{

array_temperature[i]=0; array_humidity[i]=0;

25

array_pressure[i]=0;

}

}

StatisticsDisplay::~StatisticsDisplay(void)

{

}

void StatisticsDisplay::display()

{

cout << "Average Temperature: " << average_temperature << endl; cout << "Average Humidity: " << average_humidity << endl;

cout << "Average Pressure: " << average_pressure << endl;

}

void StatisticsDisplay::update(float temperature, float humidity, float pressure)

{

for(int j=8;j>=0;j--)

{

array_temperature[j+1]=array_temperature[j]; array_humidity[j+1]=array_humidity[j]; array_pressure[j+1]=array_pressure[j];

}

array_temperature[0]=temperature; array_humidity[0]=humidity; array_pressure[0]=pressure;

float sum_temperature = 0; float sum_humidity = 0;

float sum_pressure = 0; for(int i=0;i<10;i++)

{

sum_temperature += array_temperature[i]; sum_humidity += array_humidity[i];

sum_pressure += array_pressure[i];

}

average_temperature = sum_temperature / 10; average_humidity = sum_humidity / 10; average_pressure = sum_pressure / 10;

}

6. Реализуем Наблюдателя, делающего прогнозы. Прогноз для упрощения задачи делаем

следующим образом: для прогноза на завтра, к текущим значениям прибавляем единицу.

Заголовочный файл:

#pragma once #include <iostream>

#include "observer.h" #include "DisplayElement.h" class ForecastDisplay :

public Observer, public DisplayElement

{float forecast_temperature, forecast_humidity, forecast_pressure; public:

ForecastDisplay(void);

26

~ForecastDisplay(void);

void update(float temperature, float humidity, float pressure); void display();

};

Файл реализации:

#include "ForecastDisplay.h" using namespace std;

ForecastDisplay::ForecastDisplay(void)

{

forecast_temperature=0; forecast_humidity=0; forecast_pressure=0;

}

ForecastDisplay::~ForecastDisplay(void)

{

}

void ForecastDisplay::display()

{

cout << "Forecast Temperature " << forecast_temperature << endl; cout << "Forecast Humidity " << forecast_humidity << endl;

cout << "Forecast Pressure " << forecast_pressure << endl;

}

void ForecastDisplay::update (float temperature, float humidity, float pressure)

{

forecast_temperature=temperature+1; forecast_humidity=humidity+1; forecast_pressure=pressure+1;

}

7. Реализуем интерфейс Subject, который будет связываться с интерфейсом Observers и в

задачи которого входит подписка, отписка и уведомление Наблюдателей. В интерфейсе

Subject все методы являются чистыми виртуальными. Реализация этих метод будет

сделана в классе WeatherData.

#pragma once

#include "Observer.h"

class Subject

{

virtual void registerObserver(Observer*)=0; virtual void removeObserver(Observer*)=0; virtual void notifyObserver()=0;

};

8. Реализация класса WeatherData. В классе WeatherData мы будем получить с датчиков значения температуры, влажности и давления и устанавливать эти значения (методы

27

getMeasurements и setMeasurements). Также в этом классе будет реализация методов подписки, отписки и уведомления Наблюдателей.

Заголовочный файл:

#pragma once #include "subject.h"

#include "Observer.h" class WeatherData :

public Subject

{

float temperature, humidity, pressure; Observer** observers;

public: WeatherData(void); ~WeatherData(void);

void registerObserver(Observer* a); void removeObserver(Observer* a); void notifyObserver();

void setMeasurements(float temperature, float humidity, float pressure); void getMeasurements();

};

Файл реализации:

#include <iostream> using namespace std;

#include "WeatherData.h"

WeatherData::WeatherData(void)

{

this->observers=new Observer*[3]; for (int i=0; i<3; i++)

{

this->observers[i]=0;

}

}

WeatherData::~WeatherData(void)

{

delete []observers;

}

void WeatherData::registerObserver(Observer *a)

{

for (int i=0; i<3; i++)

{

if(observers[i] == 0)

{

observers[i]=a; return;

}

}

cout << "No positions for Observer " << endl;

}

void WeatherData::removeObserver(Observer* a)

28

{

for (int i=0; i<3; i++)

{

if(observers[i] == a)

{

observers[i]=0; return;

}

}

cout << "Observer is not in the list " << endl;

}

void WeatherData::notifyObserver()

{

for (int i=0; i<3; i++)

{

if(observers[i] !=0)

{

observers[i]->update(this->temperature, this->humidity, this->pressure);

}

}

}

void WeatherData::setMeasurements(float temperature, float humidity, float pressure)

{

this->temperature=temperature; this->humidity=humidity; this->pressure=pressure; this->notifyObserver();

}

void WeatherData::getMeasurements()

{

float temperature, humidity, pressure; cout << "T= ";

cin >>temperature; cout << "H= "; cin >>humidity; cout << "P= "; cin >>pressure;

this->setMeasurements(temperature, humidity, pressure);

}

9. Создаем реализацию, т.е. функцию main(). Подключаем все необходимые классы и интерфейсы. Заводим переменные с типами наблюдателей и основного класса WeatherData. Регистрируем всех Наблюдателей. Получаем значения с датчиков и отображаем значения, полученные нашими Наблюдателями.

#include <iostream> using namespace std; #include "WeatherData.h"

#include "CurrentDisplay.h" #include "ForecastDisplay.h" #include "StatisticsDisplay.h" #include <conio.h>

void main ()

{

WeatherData a; ForecastDisplay b;

29

StatisticsDisplay c;

CurrentDisplay d;

a.registerObserver(&b);

a.registerObserver(&c);

a.registerObserver(&d);

while (1)

{

a.getMeasurements();

b.display();

c.display();

d.display();

}

getch();

}

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

Индивидуальные задания

Вариант 1

Необходимо реализовать гоночное табло, на котором будет отображаться следующая информация: для данного круга – текущая позиция, средняя скорость и время прохождения круга; статистическая информация за 3 последних круга – позиции за 3

круга, средняя скорость и среднее время прохождения круга.

Вариант 2

Реализовать табло для отображения курсов валюты: валюта может быть – доллары,

евро, фунты. Табло работает в 2-х режимах: в 1 отображается текущее значение курсов, во втором отображается среднее значение за 1 неделю.

Вариант 3

Реализовать систему рассылку электронной почты. Система находится на стадии тестирования, поэтому количество подписавшихся на рассылку будет всего трое. 1

участник подписан на экономические новости и новости спорта. 2 участник подписан на экономические новости и культурные события города. 3 участник подписан на новости науки и искусство программирования.

30

Соседние файлы в предмете Системы управления