Читайте также:
|
|
Подія − це елемент класу, який дозволяє об’єктам цього класу відправляти повідомлення іншим об’єктам про зміну свого стану. При цьому для об’єктів, які є спостерігачами події, активізуються методи-реакції (методи-обробники чи то просто обробники) цієї події. Методи-реакції мають бути зареєстровані у об’єкті-джерелі події. Отже, механізм подій є нічим іншим як способом формалізації шаблону «спостерігач», який ми розглядали у попередній темі.
Розглянемо використання механізму подій на прикладі спрощеного варіанту об’єктно-орієнтованої програми дослідження функцій у відповідності до наступної діаграми:
Мал. 1. Діаграма об’єктів задачі дослідження функції.
Спочатку наведемо приклад реалізацій класів об’єктів нашої задачі.
// клас обєкта «Головне меню» class MainMenu { // пункти головного меню string[] items; // номер обраного пункту головного меню char SelectedItem; // конструктор без параметрів public MainMenu() { items = new string[4]; items[0] = "Sin(x)"; items[1] = "Cos(x)"; items[2] = "Exp(x)"; items[3] = "Вихiд"; } // метод виводу головного меню на консоль public void Show() { Console.Clear(); Console.WriteLine("Програма дослiдження функцiй"); for (int i = 0; i < items.Length; i++) Console.WriteLine("{0} - {1}",i+1, items[i]); Console.Write("Ваш вибiр "); SelectedItem = Console.ReadKey().KeyChar; if (SelectedItem == '4') return; } } // клас обєкта «Функція» class Function { delegate double ElementaryFunction(double x); // ототожнюється з номером функції public ElementaryFunction f; } // клас обєкта «Табулятор» class Tabulator { // лівий кінець відрізку, на якому проводиться табулювання функції double a; // правий кінець відрізку, на якому проводиться табулювання функції double b; // крок табулювання double step; // точка із відрізку [a,b] double X; // значення функції у точці Х double Y; // метод побудови таблиці значень функції void BuildTable() { X = a; Console.WriteLine(" ----- X ----- Y ----- "); while(X<=b) { Console.WriteLine("| {0,8:0.000} | {1,8:0.000} |", X, Y); X+=step; } } } |
Перейдемо тепер до питання реалізації механізму подій у класах об’єктів задачі. У загальному випадку механізм подій передбачає створення події та обробку події.
1. Створення події передбачає наступні кроки.
1.1. Опис делегата, який задає сигнатуру методів-обробників події. У мові C# при описі делегата, який задає сигнатуру методів-обробників подій, загальноприйнятним є дотримання наступних правил:
§ ім’я делегата закінчується суфіксом EventHandler;
§ делегат отримує два параметри:
o перший параметр задає джерело (відправника) події та має тип object;
o другий параметр задає аргументи події − додаткові параметри, які надають обробникам події специфічну інформацію про цю подію. Якщо є необхідність у аргументах події, то для цього створюють похідний клас (ім’я якого закінчується суфіксом EventArgs) від стандартного класу System.EventArgs, в який додають необхідну інформацію.
o Якщо обробникам події не потрібні аргументи події, то при оголошенні відповідної події використовують стандартний делегат System.EventHandler:
[SerializableAttribute] [ComVisibleAttribute(true)]public delegate void EventHandler(оbject sender, EventArgs e); |
У нашій програмі є дві події: вибір конкретної функції у головному меню та отримано нове значення у табуляторі. Відповідно потрібно описати два делегати. Ці делегати опишемо у просторі імен MyEvents та програмно реалізуємо у окремому файлі MyEventHandler.cs. З урахуванням зазначених вище загальноприйнятих домовленостей маємо:
public delegate void ItemSelectEventHandler(object sender, ItemSelectEventArgs e); public delegate void CalculateEventHandler(object sender, CalculateEventArgs e); |
Відповідні класи аргументів цих подій опишемо у просторі імен MyEvents та програмно реалізуємо у окремому файлі MyEventArgs.cs:
public class ItemSelectEventArgs: System.EventArgs { char _SelectedItem; public ItemSelectEventArgs(char item) { _SelectedItem = item; } public char SelectedItem { get { return _SelectedItem; } } } public class NewXEventArgs: System.EventArgs { double x; public double Y; public NewXEventArgs(double arg) { x = arg; } public double X { get { return x; } } } |
1.2. Опис події. Оголошення події здійснюється у класі відповідного об’єкта-джерела. У найпростішому варіанті загальний синтаксис опису події наступний:
[атрибути] [специфікатори] event тип імя_події; |
При описі подій можуть бути застосованими специфікатори new, public, protected, internal, private, static, virtual, sealed, override, abstract та extern. Наприклад, так само як і методи подія може бути статичною, тоді вона стосується класу в цілому. Тип події − це тип делегата, на якому базується подія. Оголошення подій у класах відповідних об’єктів нашої задачі наступне:
class MainMenu { ... // оголошення події про вибір пункту головного меню, тобто про вибір конкретної функції public event ItemSelectEventHandler ItemSelect; } class Tabulator { ... // оголошення події обчислення нового табличного значення public event NewXEventHandler NewX; } |
1.3. Опис метода (методів), які породжують (ініціюють) подію. У класі об’єкта-джерела повинен бути визначений метод (методи), який би забезпечував настання події − у відповідний момент гарантував сповіщення всіх зареєстрованих спостерігачів про зміну стану об’єкта. Загальноприйнятим у мові C# є складати ім’я методу, що ініціює подію, із префікса On та імені події.
class MainMenu { ... // метод виводу головного меню на консоль public void Show() { Console.Clear(); Console.WriteLine("Програма дослiдження функцiй"); for (int i = 0; i < items.Length; i++) Console.WriteLine("{0} - {1}",i+1, items[i]); Console.Write("Ваш вибiр "); SelectedItem = Console.ReadKey().KeyChar; if (SelectedItem == '4') return; // ініціювання події вибору пункту головного меню OnNewItemSelect(new ItemSelectEventArgs(SelectedItem)); } ... // метод, який ініціює подію вибору нового пункту головного меню public void OnNewItemSelect(ItemSelectEventArgs e) { if (ItemSelect!= null) ItemSelect(this, e); } } class Tabulator { ... void BuildTable() { X = a; // ініціювання події про отримання нового значення X OnNewX(new NewXEventArgs(X)); Console.WriteLine(" ----- X ----- Y ----- "); while(X<=b) { Console.WriteLine("| {0,8:0.000} | {1,8:0.000} |", X, Y); X+=step; // ініціювання події про отримання нового значення X OnNewX(new NewXEventArgs(X)); } } ... // метод, який ініціює подію отримання нового значення X public void OnNewX(NewXEventArgs e) { if (NewX!= null) { NewX(this, e); Y = e.Y; } } } |
2. Обробка події здійснюється в класах об’єктів-спостерігачів (об’єктів-отримувачів повідомлення). Для цього у відповідних класах описуються методи-обробники події, сигнатура яких має відповідати типу делегата оголошеного у пункті 1.1. Для нашої визначимо методи-реакції наступним чином:
class Function { ... public void SelectFunction(object sender, ItemSelectEventArgs e) { if (sender is MainMenu) { switch (e.SelectedItem) { case '1': f = Math.Sin; break; case '2': f = Math.Cos; break; case '3': f = Math.Exp; break; } } } //реакція на обчислення нового значення X у табуляторі public void Calculate(object sender, NewXEventArgs e) { if(sender is Tabulator) e.Y=f(e.X); } } class Tabulator { ... // реакція на подію, коли вибрана функція public void Activate(object sender, ItemSelectEventArgs e) { if (sender is MainMenu) { Console.Clear(); Console.Write("a= "); a = double.Parse(Console.ReadLine()); Console.Write("b= "); b = double.Parse(Console.ReadLine()); Console.Write("Введiть крок: "); step = double.Parse(Console.ReadLine()); BuildTable(); Console.ReadKey(); } } } |
3. Реєстрація на подію. Кожен об’єкт, який хоче отримувати повідомлення, повинен зареєструвати в об’єкті-джерелі (відправнику) метод-обробник події, який був реалізований у пункті 2. Оскільки події підтримують операції += та -=, які додають метод-обробник у список та видаляють його зі списку, то вже не потрібно описувати метод реєстрації на подію.
class Program { static void Main(string[] args) { MainMenu MyMainMenu = new MainMenu(); Function MyF = new Function(); Tabulator MyTable = new Tabulator(); // реєстрація спостерігачів на події MyMainMenu.ItemSelect += MyF.SelectFunction; MyMainMenu.ItemSelect += MyTable.Activate; MyTable.NewX += MyF.Calculate; // програма починається із виводу головного меню на консоль MyMainMenu.Show(); } } |
Дата добавления: 2015-10-26; просмотров: 164 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Делегати в якості параметрів | | | Mussorgsky Jazz Orchestra |