Чтение онлайн

ЖАНРЫ

ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание

Троелсен Эндрю

Шрифт:

// Приемник событий Car.

public class CarEventSink: IEngineEvents {

 private string name;

 public CarEventSink{}

 public CarEventSink(string sinkName) { name = sinkName; }

 public void AboutToBlow(string msg) { Console.WriteLine("{0} сообщает: {1}", name, msg); }

 public void Exploded(string msg) { Console.WriteLine(" {0} сообщает: {1}", name, msg); }

}

Теперь,

когда у нас есть объект-приемник, реализующий интерфейс событий, нашей следующей задачей является передача ссылки на этот приемник в тип Car. Тип Car будет хранить эту ссылку и при необходимости выполнять обратные вызовы приемника. Чтобы тип Car мог получить ссылку на приемник, нужно добавить в тип Car вспомогательный член, который мы назовем Advise. Точно так же. если вызывающая сторона пожелает отменить привязку к источнику событий, она может вызвать другой вспомогательный метод типа Car – метод Unadvise. Наконец, чтобы позволить вызывающей стороне регистрировать множество приемников событий (с целью групповой адресации), тип Car поддерживает ArrayList для представления исходящих соединений.

// Тип Car и вызывающая сторона могут связываться

// с помощью интерфейса IEngineEvents.

public class Car {

 // Набор связанных приемников.

 ArrayList clientSinks = new ArrayList;

 // Присоединение к источнику событий или отсоединение от него.

 public void Advise(IEngineEvents sink) {clientSinks.Add(sink);}

 public void Unadvise(IEngineEvents sink) {clientSinks.Remove(sink);}

 …

}

Чтобы на самом деде посылать события, мы обновим метод Car.Accelerate так, чтобы он осуществлял "проход" по соединениям, указанным в ArrayList, и при необходимости выдавал подходящее сообщение (обратите внимание на то, что теперь в классе Car есть член-переменная carIsDead логического типа для представления состояния двигателя машины).

// Протокол событий на базе интерфейса.

class Car {

 …

 // Эта машина работает или нет?

 bool carIsDead;

 public void Accelerate(int delta) {

// Если машина 'сломалась', отправить событие Exploded

// каждому приемнику.

if (carIsDead) {

foreach(IEngineEvents e in clientSinks) e.Exploded("Извините, машина сломалась…");

} else {

currSpeed += delta;

// Отправка события AboutToBlow.

if (10 == maxSpeed – currSpeed) {

foreach(IEngineEvents e in clientSinks) е.AboutToBlow("Осторожно! Могу сломаться!");

}

if (currSpeed ›= maxSpeed) carIsDead = true;

else Console.WriteLine(" \tCurrSpeed = {0} ", currSpeed);

}

 }

}

Вот

подходящий программный код клиента, в котором используется интерфейс обратного вызова для отслеживания событий Car.

// Создание машины и мониторинг событий.

public class CarApp {

 static void Main(string[] args) {

Console.WriteLine("*** Интерфейсы и контроль событий ***");

Car cl = new Car("SlugBug", 100, 10);

// Создание объекта-приемника.

CarEventSink sink = new CarEventSink;

// Передача Car ссылки на приемник.

cl.Advise(sink);

// Ускорение (вызывает наступление событий).

for (int i = 0; i ‹ 10; i++) cl.Accelerate(20);

// Разрыв связи с источником событий.

cl.Unadvise(sink);

Console.ReadLine;

 }

}

На рис. 8.1 показан конечный результат работы этого основанного на интерфейсе протокола событий.

Рис. 8.1. Основанный на интерфейсе протокол событий

Обратите внимание на то, что метод Unadvise позволяет вызывающей стороне селективно отключаться от источника событий. Здесь перед выходом из Main вызывается Unadvise, хотя, строго говоря, это и не обязательно. Но предположим, что приложение должно зарегистрировать два приемника, динамически отключить их по очереди в процессе выполнения, а затем продолжить работу.

static void Main(string[] args) {

 Console.WriteLine("***** Интерфейсы и контроль событий *****");

 Car cl = new Car("SlugBug", 100, 10);

 // Создание двух объектов.

 Console.WriteLine("***** Создание приемников *****");

 CarEventSink sink = new CarEventSink("Первый приемник");

 CarEventSink myOtherSink = new CarEventSink("Второй приемник");

 // Передача приемников объекту Car.

 Console.WriteLine("\n***** Отправка приемников в Car *****");

 cl.Advise(sink);

 cl.Advise(myOtherSink);

 // Ускорение (при этом генерируются события).

 Console.WriteLine("\n***** Ускорение *****");

 for (int i = 0; i ‹ 10; i++) cl.Accelerate(20);

 // Отключение первого приемника событий.

Поделиться с друзьями: