Реалізація обробки подій на c - програмні продукти

Подією (event) називається вихідний дзвінок. Цей термін, напевно, добре знайомий тим, хто працює з такими мовами, як Delphi, Visual Basic і т.д. При виникненні події відбувається виклик всіх його обробників. Так як об'єкт-ініціатор події може нічого не знати про обробниках, то подія називають вихідним викликом. Робота події відбувається за принципом "від одного об'єкта до кількох". Важливо відзначити, що подія (event) і повідомлення (message) це різні поняття. Сполученням називається прямий виклик, який передається від об'єкта до об'єкта. Тобто у повідомлення є один обробник.

Події застосовуються досить широко. Прикладом можуть слугувати різні бібліотеки, реалізують графічний интерфес користувача. Але події при правильному застосуванні можуть виявитися ДІЙСНО корисною річчю На жаль історично склалося так, що в C ++ немає подій. Тому при необхідності розробники реалізують їх на рівні бібліотеки. Тут вашій увазі представлена ​​реалізація однієї такої бібліотеки. У ній є два класи: Delegate і Event.

Клас Delegate (делегат)

Клас делегат розширює поняття покажчика на функцію. Використовуючи цей клас Ви можете передати посилання на метод об'єкту-делегату. Далі об'єкт-делегат може бути переданий клієнтського коду, який може побічно викликати метод. При цьому код, який звертається з делегатом не знає що за метод ховається за ним. Перевага делегата полягає в тому, що Ви можете динамічно передавати йому покажчики на методи і тим самим змінювати поведінку програми без перекомпіляції клієнтського коду. Програма, що використовує делегат буде залишатися в щасливому невіданні про ваших маніпуляціях з методами і їх власниками.

Приклади використання класу Delegate

Результати роботи цієї програми повинні бути наступними:

Розберемо програму докладніше. Спочатку ми підключаємо заголовки класу Delegate:

Делегат передає цей виклик тієї функції, на яку він вказує. Якщо ж делегат містить NULL, то виклик ігнорріруется. Далі ми міняємо функцію, на яку вказує делегат:

Для демонстрації отриманого ефекту повторно робимо виклик. При цьому відбувається виклик функції Test :: SayGoodBye ().

Даний приклад досить простий, але все ж він демонструє можливості, якими володіють делегати і їх основні переваги.

Приклад №2: Невелика база даних

Але найважливішою функцією в класі, а можливо і у всій програмі є функція ProcessStaff (Delegate ). За допомогою цього методу можна для кожного з працівників, які перебувають в колекції _staff зробити виклик методу, який ховається за делегатом. Далі в основної функції програми main виробляються кілька таких викликів.

Клас бухгалтера надає наступні можливості. Він дозволяє вести облік робочого за допомогою методу AddEmployeToAccount (Employe *). При виконанні цього методу лічильник працівників _count збільшується на 1, а до загальної зарплати _totalWage додається зарплата даного працівника, яка обчислюється за допомогою методу Employe :: CalculateWage (). Метод GetTotalWage () повертає кількість грошей, які виплачуються всім робочим як зарплату. GetAverageWage () обчислює середню зарплату по підприємству.

Нарешті прийшов час написати головну функцію програми. Її реалізація представлена ​​нижче

Результат виконання програми наведено на малюнку нижче

Розберемося, що ж відбувається в цій програмі. По-перше, слід зазначити новий клас, який виконує в основному допоміжні функції. Цей клас називається EmployeTester. Він має два методи. Перший з них - PrintInfo (Employe *) роздруковує інформацію про співробітника, який передається йому як параметр. Другий метод AddEmployes (EnterpriseDB *) просто заповнює базу даних декількома співробітниками.

Ну а зараз перейдемо до розгляду головної функції програми. Саме в ній відбуваються найголовніші події, пов'язані з використанням делегатів. Спочатку програма створює базу даних, бухгалтера і об'єкт EmployeTester:

Потім в базу даних вносяться відомості про трьох працівників:

Після установки нарахувань службовцям в справу вступає об'єкт EmployeTester. Він виводить на екран інформацію про кожного з робітників:

А зараз прийшов час бухгалтеру підрахувати всіх робітників і визначити сумарну зарплату і середню зарплату по підприємству. Результати виводяться на екран:

Підведемо підсумки. Делегати зручно застосовувати в наступних випадках:
  • Потрібно викликати тільки один метод
  • Зухвалому коду не потрібно знати про об'єкт, якому належить метод
  • Клас може мати кілька реалізацій одного методу

Клас Event (подія)

Подія в даному випадку - це спосіб для класу сповістити своїх клієнтів (класів, які використовують даний клас) про те, що з ним сталося щось цікаве. Напевно самий знайомий спосіб використання подій - в графічному інтерфейсі користувача (GUI). Зазвичай класи, що представляють елементи управління (controls) в графічному інтерфейсі мають події, які спрацьовують, коли користувач щось робить з елементом управління (наприклад, натискає на кнопку). Але події можуть бути використані не тільки в графічному інтерфейсі. Події обеспечіает дійсно корисний шлях для об'єктів сигналізувати про зміну свого стану. Причому ця зміна може бути важливо для клієнтів даного об'єкта. Події - це важливі будівельні блоки для створення класів, які можуть бути повторно використані в багатьох програмах. Події використовуються безпосередньо разом з делегатами. Важливо пам'ятати, що об'єкти - делегати інкапсултруют (приховують) метод класу і він може бути викликаний анонімно. Подія - це спосіб викликати методи інших об'єктів, коли подія спрацьовує. Тобто сторонній об'єкт поміщає покажчик на свій метод в делегат (як було показано раніше) і передає цей делегат події. При спрацьовуванні події викликається делегат, а отже і той метод, який був йому переданий.

Приклад використання класу Event

Результат виконання програми наведено нижче на малюнку.

Обговоримо код. У цій програмі задіяні три класи. Спочатку розглянемо клас Color. який описує колір. У ньому є такі компоненти:
  • Червона, зелена і синя складові кольору (RGB)
  • Рядок display. предназнвченная для виведення кольору на екран

Для зручності поводження з класом оголошені кілька статичних констант - White, Black, Red, Green, Blue. Використовувати клас Color можна наступним чином:

Функція ToString () перетворює значення кольору в рядок.

Наступний клас називається View. Він містить в собі одну змінну визначальну колір. Клас надає методи для отримання / установки значення кольору - це відповідно GetColor / SetColor. Також в класі View є подія ColorChanged. яке спрацьовує, коли програма змінює значення кольору, тобто викликає метод SetColor.

NewView - є похідним класом від View. Його робота полягає в тому, щоб додати свою функцію в подія ColorChanged. яке належить його предку. Робиться це в конструкторі NewView:

Як видно, для того, щоб передати свою функцію події потрібно спочатку створити для неї обгортку у вигляді делегата, а потім "додати" делегат до події оператором + =.

"Спостерігач" за подіями (EventListener) фактично надходить також як і клас NewView. Він отримує покажчик на View і додає до події ColorChanged свій метод EventListener :: React ():

Метод EventListener :: Detach () від'єднує від події свій метод React:

Від'єднання методу відбувається так само як і приєднання, тільки використовується оператор - =.

Розглянемо головну функцію програми. Спочатку програма створює об'єкти EventListener і NewView і виводить початкове значення кольору в об'єкті NewView:

Слід звернути увагу що на цей момент до події ColorChanged приєднані два методу - це NewView :: OnColorChanged () і EventListener :: React (). У цьому можна переконатися, змінивши значення кольору методом SetColor. В результаті будуть викликані дві вищезгадані функції. Далі об'єктом EventListener проводиться від'єднання свого методу від події. Повторно викликавши метод SetColor переконуємося, що на подію реагує тільки один метод - NewView :: OnColorChange ():

останні зауваження

Якщо Ви хочете використовувати класи Delegate і Event в своїх проектах, підключіть до них файли Delegate.h, Event.h, EventBase.h і EventBase.cpp.