Все мы знаем, что программирование может быть сложным, и иногда нам приходится выполнять много задач одновременно. Но как сделать так, чтобы всё работало правильно и быстро? В этой статье я расскажу вам о том, как можно написать класс, который поможет вам легко управлять всеми этими задачами и сделает вашу жизнь как программиста проще.
Готовы начать?
Представьте, что вы работаете над системой обработки данных с сервера. У вас есть общий класс-родитель, который отвечает за получение данных от сервера. Этот класс - родитель для нескольких потомков, каждый из которых имеет свои собственные задачи при получении данных.
Например, один потомок должен анализировать данные, другой - сохранять их в базу данных, а третий - отображать на интерфейсе. Используя событийную систему, вы можете добавить в родительский класс очереди функций обратного вызова для каждого потомка. Каждый потомок может зарегистрировать свои функции в этой очереди, и родительский класс будет вызывать их в соответствии с событиями (например, получение данных от сервера). Таким образом, вы можете обеспечить разные действия для разных потомков, не изменяя родительский класс.
Для лучшего понимания, давайте рассмотрим простой пример, который иллюстрирует, как можно использовать событийную систему и очереди функций обратного вызова для решения нашей задачи. Предположим, у нас есть следующая иерархия классов:
- ServerDataReceiver - родительский класс для получения данных с сервера.
- DataAnalyzer - потомок, отвечающий за анализ полученных данных.
- DatabaseSaver - потомок, сохраняющий данные в базу данных.
- UIUpdater - потомок, обновляющий интерфейс.
Теперь, когда у нас есть иерархия классов, где каждый класс получает данные от сервера, но необходимо обработать данные без изменения родительской функции приема данных, давайте рассмотрим решение, которое позволит нам это сделать. В данном случае на помощь приходят функции обратного вызова.
Не изменяя логики работы родительской функции приема данных, мы воспользуемся новым классом FunctionQueue. Этот класс позволит нам создавать и управлять очередями функций обратного вызова.
Давайте рассмотрим, как этот новый класс выглядит:
Из стандартных заголовков нам понадобятся:
- functional - для более удобной работой с функциями.
- vector - для массива функций.
И так, так как у нас будет использоваться массив функций, то используем std::vector<std::function<void()>> - std::function<void()> показывает, что функция не будет ничего возвращать и принимать аргументы, все потому, что мы будем использовать лямбда функции.
Функция класса Clear пригодится, если потребуется зачистить вектор.
Перегруженный оператор += будет использован для добавления функций в вектор.
Перегруженный оператор (), для вызова всех функций в векторе.
Хорошо, класс написан, но как им пользоваться дальше?
Всё очень просто, так как в классе ServerDataReceiver есть экземпляр нашего класса, то все потомки могут использовать следующею запись:
В данном примере потомки класса регистрируют свои функции для выполнения их после получения данных, тем самым мы не задумываемся о том, что нужно отслеживать когда придут данные и тем самым упрощаем себе работу.
Как только данные приходят, автоматически вызывается функция нашего класса OnCallBack() тем самым, не требуя от потомка следить за временем получения данных.
Таким образом, использование данного класса делает код более читаемым и упрощает взаимодействие между родительским и потомками классов, обеспечивая гибкость и разделение обязанностей.