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


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

Кадр

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

На приведенной диаграмме присутствуют в основном те же классы которые были определены на этапе анализа. Отличие в том что на этой диаграмме видно каким образом ключевые абстракции нашего ключевого приложения взаимодействуют друг с другом. Например, не воспроизведена иерархия классов датчиков. Кроме этого вводится новый класс, Sensors который, служит для объединения в контейнер всех объектов датчика. Поскольку, по крайней мере, два объекта (Sample и InputManager) в нашей системе должны ассоциироваться с целой коллекцией датчика. Помещение их в один контейнерный класс позволяет рассматривать все датчики единым образом.
Механизм покадровой обработки:
Поведение системы в основном определяется взаимодействием классов Sampler и Timer. Определим вначале внешний интерфейс для класса Timer, осуществляющего диспетчеризацию функции обратного вызова.
typedef unsigned int Tick
class Timer{
public:
static setCallBack(void(*)(Tick));
static startTiming();
static Tick numberofTick();
private:

};
Прежде чем перейти к классу Sampler, введем перечисляемый тип всех датчиков, присутствующих в системе:
enum SensorName{Direction, Speed, WindChill, Temperature, DewPoint, Humidity, Pressure};
class Sampler{
public:
Sampler();
~Sampler();
//установить частоту опроса
void setSamplingRate(SensorName, Tick);
void Sample (Tick);//опрос
Tick SamplingRate() const;//частота опроса
protected:
…};
Чтобы обеспечить связь м/у классами Timer и Sampler, требуется некоторое дополнение. Определим фрагмент кода, в котором создается объект класса Sampler, и определяется внеклассовая функция acquire.

Sampler sampler;
Void acquire(Tick){
sampler.sample(t)
}
После этого можно написать функцию main, где происходит присоединение к Timer-у функции обратного вызова и запускается процесс опроса датчика:
main() {
Timer:: setCallBack(acquire);
Timer:: startTiming();
while(1){
;
}
return (0);
}
Это довольно типичная для ОО-системы главная функция. Она короткая (т.к. основная работа делегирована объектом) и включает в себя цикл диспетчеризации. (В нашем случае пустой, т.к. отсутствуют какие-либо фоновые процессы)
Далее определяем внешний интерфейс класса Sensors.
class Sensors: protected collections{
public:
Sensors();
virtual ~Sensors();
void add sensor (const sensor&sensorName, unsigned int id=0);
unsigned int number of Sensors() const;
unsigned int number of Sensors(sensorName);
sensor&sensor(sensorName, unsigned int id=0 );
protected:
… };
Это в основном класс-коллекция, поэтому он объявляется подклассом фундаментального класса Сollection. Класс Сollection указан как защищенный супер класс. Это сделано для того, чтобы скрыть детали его строения от клиентов класса Sensors.
Т.о. создан класс-коллекция для датчиков, который может содержать мн-во экземпляров датчиков одного и того же типа, при чем каждый экземпляр своего вида имеет уникальный идентификационный номер, начиная с нуля.
Вернемся к спецификации класса Sampler. Необходимо обеспечить его ассоциацию с классом Sensors и DisplayManager:
class Sampler{
public:
Sampler(Sensors&DisplayManager);
protected:
Sensores& rep Sensors;
DisplayManager& rep DisplayManager ;
};
Приведем фрагмент кода, где происходит создание класса Sampler:
Sensors sensors;
DisplayManager display;
Sampler sampler(sensors,display);
При порождении объекта Sampler устанавливается связь м/у ним, коллекцией датчиков Sensors и экземпляром класса DisplayManager, который будет использоваться системой.
В заключение следует заняться описанием центральной операции класса Sampler — sample.
void Sampler :: sample(Tick t){
for (SensorName name=Direction; name<=Pressure; name++)
for(unsigned int id=0; id<=rep sensors.numberOfSensors(name); id++)
if(!(t % SamplingRate(name)))
rep DisplayManager.display(rep Sensors.sensor(name,id).currentValue(),name,id);
}
Эта функция по очереди опрашивает каждый тип датчика, и каждый датчик внутри типа. Она проверяет, пришло ли время считывать информацию с датчика, и, если да, то определяет ссылку на датчик в коллекции, считывает его текущее значение и передает его менеджеру дисплея, ассоциированному с данным экземпляром класса Sampler.
Семантика этой операции основывается на полиморфном поведении сл. метода:
}/ virtual float current value();
определенного для базового класса Sensor. Эта операция кроме того основывается на функции класса DisplayManager.display.
Диаграмма классов механизма по кадровой обработки.

Загрузка...