русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Лекция 1. Элементы Языка СИ


Дата добавления: 2013-12-23; просмотров: 1106; Нарушение авторских прав


Классы с большим числом событий

Как было сказано, каждое событие класса представляется полем этого класса. Когда у класса много объявленных событий, а реально возникает лишь малая часть из них, то предпочтительнее динамический подход, когда память отводится только фактически возникшим событиям. Это несколько замедляет время выполнения, но экономит память. Решение зависит от того, что в данном контексте важнее – память или время. Для реализации динамического подхода в языке предусмотрена возможность задания пользовательских методов Add и Remove в момент объявления события. Это и есть другая форма объявления события, упоминавшаяся ранее. Вот ее примерный синтаксис:

public event <Имя Делегата> <Имя события>

{



add {…}

remove {…}

}

Оба метода должны быть реализованы, при этом для хранения делегатов используется некоторое хранилище. Именно так реализованы классы для большинства интерфейсных объектов, использующие хэш-таблицы для хранения делегатов.

Давайте построим небольшой пример, демонстрирующий такой способ объявления и работы с событиями. Вначале построим класс с несколькими событиями:

class ManyEvents

{



//хэш таблица для хранения делегатов

Hashtable DStore = new Hashtable();

public event EventHandler Ev1

{



add

{



DStore["Ev1"]= (EventHandler)DStore["Ev1"]+ value;

}

remove

{



DStore["Ev1"]= (EventHandler)DStore["Ev1"]- value;

}

}

public event EventHandler Ev2

{



add

{



DStore["Ev2"]= (EventHandler)DStore["Ev2"]+ value;

}

remove

{



DStore["Ev2"]= (EventHandler)DStore["Ev2"]- value;

}

}

public event EventHandler Ev3

{



add

{



DStore["Ev3"]= (EventHandler)DStore["Ev3"]+ value;

}

remove

{



DStore["Ev3"]= (EventHandler)DStore["Ev3"]- value;

}

}

public event EventHandler Ev4

{



add

{



DStore["Ev4"]= (EventHandler)DStore["Ev4"]+ value;

}

remove

{



DStore["Ev4"]= (EventHandler)DStore["Ev4"]- value;

}

}

public void SimulateEvs()

{



EventHandler ev = (EventHandler) DStore["Ev1"];

if(ev != null) ev(this, null);

ev = (EventHandler) DStore["Ev3"];

if(ev != null) ev(this, null);

}

}//class ManyEvents

В нашем классе четыре события и хэш-таблица DStore для их хранения. Все события принадлежат встроенному классу EventHandler. Когда к событию будет присоединяться обработчик, автоматически будет вызван метод add, который динамически создаст элемент хэш-таблицы, Ключом элемента является в данном случае строка с именем события. При отсоединении обработчика будет исполняться метод remove, выполняющий аналогичную операцию над соответствующим элементом хэш-таблицы. В классе определен также метод SimulateEvs, при вызове которого зажигаются два из четырех событий – Ev1 и Ev3.

Рассмотрим теперь класс ReceiverEvs, слушающий события. Этот класс построен по описанным ранее правилам. В нем есть ссылка на класс, создающий события; конструктор с параметром, которому передается реальный объект такого класса; четыре обработчика события – по одному на каждое событие, и метод OnConnect, связывающий обработчиков с событиями. Вот код класса:

class ReceiverEvs

{



private ManyEvents manyEvs;

public ReceiverEvs( ManyEvents manyEvs)

{



this.manyEvs = manyEvs;

OnConnect();

}

public void OnConnect()

{



manyEvs.Ev1 += new EventHandler(H1);

manyEvs.Ev2 += new EventHandler(H2);

manyEvs.Ev3 += new EventHandler(H3);

manyEvs.Ev4 += new EventHandler(H4);

}

public void H1(object s, EventArgs e)

{



Console.WriteLine("Событие Ev1");

}

public void H2(object s, EventArgs e)

{



Console.WriteLine("Событие Ev2");

}

public void H3(object s, EventArgs e)

{



Console.WriteLine("Событие Ev3");

}

public void H4(object s, EventArgs e)

{



Console.WriteLine("Событие Ev4");

}

}//class ReceiverEvs

Тестирующая процедура состоит из нескольких строчек, в которых создаются нужные объекты, и запускается метод Simulate, зажигающий события:

public void TestManyEvents()

{



ManyEvents me = new ManyEvents();

ReceiverEvs revs = new ReceiverEvs(me);

me.SimulateEvs();

}

Все работает предусмотренным образом.

Проект «Город и его службы»

Завершить лекцию о событиях хочется содержательным учебным проектом, в котором моделируется жизнь города, происходящие в нем события, реакция городских служб на эти события. Наша главная цель в данном проекте еще раз показать, как возникающее событие, в данном случае – пожар в одном из домов города, обрабатывается по-разному городскими службами – пожарниками, милицией, скорой помощью. Конечно, все упрощено, в реальном городе событиями являются не только пожары и преступления, но и более приятные ситуации: день города, , открытие фестивалей и выставок, строительство новых театров и институтов.

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

 

public class NewTown

{



//свойства

private int build, BuildingNumber; //дом и число домов в городе

private int day, days; //Текущий день года

//городские службы

private Police policeman ;

private Ambulance ambulanceman ;

private FireDetect fireman ;

//события в городе

public event FireEventHandler Fire;

//моделирование случайных событий

private Random rnd = new Random();

//вероятность пожара в доме в текущий день: p= m/n

private int m = 3, n= 10000;

В нашем городе есть дома, есть время, текущее день за днем, городские службы, событие «пожар», которое, к сожалению, может случайно с заданной вероятностью возникать каждый день в каждом доме. Рассмотрим конструктор объектов нашего класса:

//конструктор класса

public NewTown(int TownSize, int Days)

{



BuildingNumber = rnd.Next(TownSize);

days = Days;

policeman = new Police(this);

ambulanceman= new Ambulance(this);

fireman= new FireDetect(this);

policeman.On();

ambulanceman.On();

fireman.On();

}

При создании объектов этого класса задается размер города – число его домов и период времени, в течение которого будет моделироваться жизнь города. При создании объекта создаются его службы – объекты соответствующих классов Police, Ambulance, FireDetect, которым предается ссылка на сам объект «город». При создании служб, вызываются методы On, подключающие обработчики события Fire каждой из этих служб к событию.

В соответствие с ранее описанной технологией определим метод OnFire, включающий событие:

protected virtual void OnFire(FireEventArgs e)

{



if(Fire != null)

Fire(this, e);

}

Где и когда будет включаться событие Fire? Напишем метод, моделирующий жизнь города, где для каждого дома каждый день будет проверяться, а не возник ли пожар, и, если это случится, то будет включено событие Fire:

public void LifeOurTown()

{



for(day = 1; day<=days; day++)

for(build =1; build <= BuildingNumber; build++)

{



if( rnd.Next(n) <=m) //загорелся дом

{



//аргументы события

FireEventArgs e = new FireEventArgs(build, day, true);

OnFire(e);

if(e.Permit)

Console.WriteLine("Пожар потушен!" +

" Ситуация нормализована.");

else Console.WriteLine("Пожар продолжается." +

" Требуются дополнительные средства!");

}

}

}

Рассмотрим теперь классы receiver, обрабатывающие событие Fire. Их у нас три, по одному на каждую городскую службу. Все три класса устроены по одному образцу. Напомню, каждый такой разумно устроенный класс, кроме обработчика события имеет конструктор, инициализирующий ссылку на объект, создающий события, методы подключения и отсоединения обработчика от события. В такой ситуации целесообразно построить вначале абстрактный класс Receiver, в котором будет предусмотрен обработчик события, но не задана его реализация, а затем для каждой службы построить класс потомок. Начнем с описания родительского класса:

public abstract class Receiver

{



private NewTown town;

public Receiver(NewTown town)

{this.town = town;}

public void On()

{



town.Fire += new FireEventHandler(It_is_Fire);

}

public void Off()

{



town.Fire -= new FireEventHandler(It_is_Fire);

town = null;

}

public abstract void It_is_Fire(object sender, FireEventArgs e);

}//class Receiver

Для классов потомков абстрактный метод It_is_Fire будет определен. Вот их описания:

public class Police : Receiver

{



public Police (NewTown town): base(town){}

public override void It_is_Fire(object sender, FireEventArgs e)

{



Console.WriteLine("Пожар в доме {0}. День {1}-й." +

" Милиция ищет виновных!", e.Build,e.Day);

e.Permit &= true;

}

}// class Police

public class FireDetect : Receiver

{



public FireDetect (NewTown town): base(town){}

public override void It_is_Fire(object sender, FireEventArgs e)

{



Console.WriteLine("Пожар в доме {0}. День {1}-й." +

" Пожарники тушат пожар!", e.Build,e.Day);

Random rnd = new Random(e.Build);

if(rnd.Next(10) >5)

e.Permit &= false;

else e.Permit &=true;

}

}// class FireDetect

public class Ambulance : Receiver

{



public Ambulance(NewTown town): base(town){}

public override void It_is_Fire(object sender, FireEventArgs e)

{



Console.WriteLine("Пожар в доме {0}. День {1}-й." +

" Скорая спасает пострадавших!", e.Build,e.Day);

e.Permit &= true;

}

}// class Ambulance

Для каждого потомка задан конструктор, вызывающий базовый метод родителя. Каждый потомок по-своему определяет обработчика события Fire. Обратите внимание на то, как в данном проекте решается проблема с выходным параметром события – Permit. Принята следующая стратегия – возвращаемое значение Permit будет истинно, если все обработчики согласны с этим. Поэтому каждый обработчик использует конъюнкцию выработанного им значения со значением, пришедшим от предыдущего обработчика. В данном примере все зависит от пожарников, которые могут вырабатывать разные решения.

Для полноты картины необходимо показать, как выглядит класс, задающий аргументы события, который, как и положено, является потомком класса EventArgs:

public class FireEventArgs : EventArgs

{



private int build;

private int day;

private bool permit;

public int Build

{



get{ return(build);}

//set{ build = value;}

}

public int Day

{



get{ return(day);}

//set{ day = value;}

}

public bool Permit

{



get{ return(permit);}

set{ permit = value;}

}

public FireEventArgs(int build, int day, bool permit)

{



this.build = build; this.day = day; this.permit = permit;

}

}//class FireEventArgs

Входные параметры события – build и day защищены от обработчиков события, а корректность выходного параметра гарантируется тщательным программированием самих обработчиков.

Для завершения проекта нам осталось определить тестирующую процедуру в классе Testing, создающую объекты и запускающую моделирование жизни города:

public void TestLifeTown()

{



NewTown sometown = new NewTown(100,100);

sometown.LifeOurTown();

}

Результаты ее работы зависят от случайностей. Вот как выглядит один из экспериментов:

Рис. 21.3. События в жизни города

Вариант 1

1. Обработчик события:

q всегда принадлежит классу, зажигающему событие;

q никогда не принадлежит классу, зажигающему событие;

q может принадлежать классу, зажигающему событие;

q принадлежит только одному классу, слушающему событие;

q может принадлежать многим классам, слушающим события.

2. Отметьте истинные высказывания:

q все события имеют одинаковую сигнатуру из двух аргументов с одними и теми же типами;

q все события имеют сигнатуру из двух аргументов, но с отличающимися типами;

q все события, не имеющие собственных аргументов, передаваемых обработчику, соответствуют стандартному встроенному делегату EventHandler;

q для класса с большим числом событий целесообразно применять динамическое связывание;

q для связывания событий с обработчиком можно применять только операцию +=.

3. Объявление события в классе может представлять собой:

q объявление метода класса;

q объявление поля класса;

q объявление процедуры-свойства класса с методами get и set;

q объявление процедуры-свойства класса с методами add и remove.

Вариант 2

1. Объекты одного класса:

q имеют одинаковый набор событий;

q в процессе вычислений зажигают одинаковый набор событий;

q в процессе вычислений зажигают набор событий, характерный для объекта;

q в разных сеансах работы зажигают одинаковый набор событий;

q в разных сеансах работы зажигают разные события.

2. Отметьте истинные высказывания:

q класс, обрабатывающий событие, может отсоединить других обработчиков события и полностью определить реакцию на событие;

q каждый объект определяет, какой обработчик присоединяется к событию;

q метод GetInvocationList не применим к событиям;

q все события имеют одну и ту же сигнатуру.

3. Класс EventHandler:

q является классом, которому принадлежат все события;

q является абстрактным классом и не может иметь экземпляров;

q является родительским классом для событий, не имеющих собственных аргументов;

q является потомком класса Delegate;

q накладывает ограничения на сигнатуру события.

Вариант 3

1. Процедура, в которой зажигается событие:

q передает обработчику событий входные аргументы и продолжает свою работу;

q передает обработчику событий входные аргументы и ждет окончания работы первого обработчика, связанного с событием;

q передает обработчику событий входные аргументы и ждет окончания работы всего списка обработчиков, связанного с событием;

q может получить от обработчиков выходные аргументы и использовать их в своей работе.

2. Отметьте истинные высказывания:

q события – это специализированный вариант делегатов;

q к каждому событию должен быть присоединен хотя бы один обработчик события;

q методы Combine и Remove, наследованные от класса Delegate не применимы к событиям;

q допустимо динамическое связывание событий с обработчиками событий.

3. Все аргументы события принадлежат:

q классу EventArgs;

q классу EventArgs, за исключением аргумента, задающего объект, зажигающий событие;

q потомку класса EventArgs;

q потомку класса EventArgs за исключением аргумента, задающего объект, зажигающий событие;

q возможно разным классам.

 



<== предыдущая лекция | следующая лекция ==>
Две проблемы с обработчиками событий | Константы


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.013 сек.