В строке 15 назначается отслеживание пороговых значений, в строке 16 отслеживание выключается. С помощью метода, объявленного в строке 17, можно создать экземпляр соответствующего интерфейсного класса.

Класс, реализующий интерфейс, приведен в Листинг 98.

Листинг 98 Класс, реализующий интерфейс (SensorControl.h)

namespace sensor

{

class ISensor;

class IDriver;

class CommandQueue;

class AlertControl;

class SensorContainer;

class SensorControl: public ISensorControl

{

  public:

    SensorControl();

    ~SensorControl();

    void initialize() override;

    /* Other Interface methods – they are not displayed here*/

  private:

    SensorContainer* sensorContainer_;   // (1)

    CommandQueue* commandQueue_;         // (2)

    AlertControl* alertControl_;         // (3)

    bool isInitialized_;                 // (4)

    DriverPointer driver_;               // (5)

    void checkInitialize();  // (6)

    void checkDriver();      // (7)

};

}; //namespace sensor

В строке 1 объявлен контейнер для хранения датчиков, в строке 2 – класс для выполнения асинхронных запросов, в строке 3 – класс для отслеживания пороговых значений. Соответствующие указатели создаются в конструкторе и уничтожаются в деструкторе. Индикатор 4 указывает, была ли выполнена инициализация.

В строке 6 объявлен вспомогательный метод, который проверяет, была ли выполнена инициализация (если нет, выбрасывает исключение). В строке 7 аналогичный метод проверяет, был ли установлен драйвер.

Рассмотрим, как здесь используются обратные вызовы. Для начала самый простой случай – чтение показаний работоспособных датчиков (Листинг 99).

Листинг 99. Обратные вызовы в классе, реализующем интерфейс (SensorControl.cpp)

void SensorControl::readSensorValues(SensorValueCallback callback)

{

  checkInitialize();  // (1)

  sensorContainer_->forEachSensor([callback](SensorNumber number, SensorPointer sensor)  // (2)

    {

      if (sensor->isOperable())  // (3)

      {

        callback(number, sensor->getValue());  // (4)

      }

    }

  );

}

В строке 1 производится проверка, инициализирован ли класс. Если класс не проинициализирован, то функция выбросит исключение.

В строке 2 происходит перебор элементов контейнера, в качестве обратного вызова используется лямбда-выражение. Контейнер будет вызывать лямбда-выражение, в которое он будет передавать номер датчика и указатель на экземпляр класса. В теле выражения проверяется, является ли датчик работоспособным (строка 3), и если да, то выполняется соответствующий обратный вызов (строка 4).

Рассмотрим теперь поиск максимального и минимального значения для заданного диапазона номеров датчиков. Вначале разработаем вспомогательный класс, который будет последовательно принимать на вход показания датчиков и искать среди них максимальное и минимальное значение (Листинг 100).

Листинг 100. Класс для анализа минимального и максимального значения (SensorControl.cpp)

class FindMinMaxValue

{

public:

  enum MinMaxSign { MIN_VALUE = 0, MAX_VALUE = 1 };  // (1)

  FindMinMaxValue(SensorNumber first, SensorNumber last, MinMaxSign sign) :  // (2)

    sign_(sign), first_(first), last_(last), count_(0)

  {

    if (sign == MIN_VALUE)

    {

      result_ = std::numeric_limits::max();  // (3)

    }

    else

    {

      result_ = std::numeric_limits::min();  // (4)

    }

    arrayFunMinMax_[MIN_VALUE] = &FindMinMaxValue::CompareMin;  // (5)

    arrayFunMinMax_[MAX_VALUE] = &FindMinMaxValue::CompareMax;  // (6)

  }

  void operator()(SensorNumber number, SensorPointer sensor)                  // (7)

  {

Перейти на страницу:

Похожие книги