Както беше вече споменато, за разлика от делегатите, събитията могат да бъдат членове на интерфейси. Следващият код илюстрира това:
Имплементиране на събития в интерфейс
При имплементация на интерфейса, имплементиращият клас трябва да предизвиква събитието, което е декларирано в интерфейса. Допустимо е освен това при конкретната имплементация класът да реализира специфични add и remove методи, с което да промени тяхното поведение по подразбиране и да добави нетривиална логика.
Когато в интерфейс се декларират свойства, имплементиращият клас е длъжен да реализира техните методи (set, get или и двата, в зависимост от декларацията). За разлика от свойствата, при събитията не е задължително да се имплементират специфични add и remove методи – ако специфична реализация липсва, те получават поведение по подразбиране, съответно да добавят и премахват обработчици на събитието.
Събития и интерфейси – пример
В настоящия пример ще разгледаме съвместната употреба на събития и интерфейси:
public delegate void ClickEventHandler(object aSender,
EventArgs aEventArgs);
public interface IClickable
{
event ClickEventHandler Click;
}
public class Button : IClickable
{
private ClickEventHandler mClick;
// Implement the event from the interface IClickable
public event ClickEventHandler Click
{
add
{
mClick += value;
Console.WriteLine("Subscribed to Button.Clicked event.");
}
remove
{
mClick -= value;
Console.WriteLine(
"Unsubscribed from Button.Clicked event.");
}
}
protected void OnClick()
{
if (mClick != null)
{
mClick(this, EventArgs.Empty);
}
}
public void FireClick()
{
Console.WriteLine("Button.FireClick() called.");
OnClick();
}
}
public class ButtonTest
{
private static void Button_Click(object aSender,
EventArgs aEventArgs)
{
Console.WriteLine("Button_Click() event called.");
}
public static void Main()
{
Button button = new Button();
button.Click +=
new ClickEventHandler(Button_Click);
button.FireClick();
button.Click -=
new ClickEventHandler(Button_Click);
}
}
|
След изпълнение на примера се получава следният резултат:
Описание на примера
В началото се декларира делегат, който ще бъде тип на събитието, дефинирано в интерфейса. След това се дефинира интерфейс IClickable с единствен член, който е събитието Click. Класът Button имплементира интерфейса IClickable, като добавя частна член-променлива от типа на делегата и реализира специфични add и remove методи за събитието, чрез които се извършва манипулация на списъка с методи на променливата-делегат. Освен това в класа се декларират методи за предизвикване на събитието и извикване на обработчиците му. Класът ButtonTest дефинира метод-обработчик на събитието Click и в главния си метод създава инстанция на класа Button, абонира се за събитието Click, предизвиква го и след това премахва абонамента.
Интерфейси, събития, делегати
В .NET Framework поведението "обратно извикване" може да се реализира чрез три механизма: делегати, събития и интерфейси. Досега разгледахме използването на делегатите и събитията.
Чрез интерфейси "обратно извикване" може да се реализира като методът, който трябва да се използва за "обратно извикване" се декларира като член на интерфейс. След това в различните класове, които имплементират интерфейса, методът може да бъде имплементиран по различни начини и така той не се обвързва с конкретна реализация. В класа, който ще извършва обръщение към callback метода се декларира променлива от типа на интерфейса, който съдържа декларацията на съответния метод. На тази променлива могат да се присвояват референции към обекти от различни класове, имплементиращи съответния интерфейс. По този начин могат да бъдат викани методи с различно поведение, в зависимост от необходимостта.
"Обратно извикване" чрез интерфейси – пример
Следващият пример показва как можем да използваме интерфейс, за да реализираме "обратно извикване":
public interface IClickListener
{
void ClickPerformed();
}
public class Button
{
private IClickListener mClickListener;
public Button(IClickListener aClickListener)
{
mClickListener = aClickListener;
}
public void DoClick()
{
if (mClickListener != null)
{
mClickListener.ClickPerformed();
}
}
}
public class ButtonTest : IClickListener
{
public static void Main()
{
ButtonTest buttonTest = new ButtonTest();
Button button = new Button(buttonTest);
button.DoClick();
}
void IClickListener.ClickPerformed()
{
Console.WriteLine("Click performed.");
}
}
|
След изпълнения на примера се получава следният резултат:
Описание на примера
Интерфейсът IClickListener съдържа метода ClickPerformed(), чрез който ще се реализира "обратно извикване". В класа Button са дефинирани член mClickListener от типа на интерфейса и метод DoClick(), който извиква интерфейсния метод ClickPerformed(). Класът ButtonTest имплементира интерфейса IClickListener и в главната си функция създава обект от тип Button и извиква метода му DoClick(). При това се извиква имплементацията на ClickPerformed(), която е предоставена от ButtonTest.
Кога да използваме интерфейси?
Въпреки че "обратно извикване" може да се реализира чрез интерфейси, това не е типично приложение на интерфейс и е добре да се използва по-рядко. Докато делегатите дават възможност за извикване на множество методи, то всички те трябва да имат еднакъв връщан тип и сигнатура. При интерфейсите няма такова ограничение, и затова те трябва да се ползват именно когато е нужно даден обект да предоставя съвкупност от много различни callback методи.
Кога да използваме събития?
Събитията се използват, когато разработваме компоненти, които трябва да известяват своя притежател за нещо, обикновено за промяна в текущото състояние или за извършване на някакво действие. Освен това чрез използване на събитията се поддържа съвместимост с компонентния модел на .NET.
Кога да използваме делегати?
Основните приложения на делегатите са за асинхронна обработка посредством callback методи и за даване на възможност на потребителите на клас да предоставят метод, извършващ специфична обработка, която не е предварително фиксирана. В този случай извикването на callback метода не е свързано с настъпването на някаква промяна или събитие, както е при събитията. Делегатите се използват, когато имаме единичен callback метод, който не е свързан с компонентния модел на .NET.
Сподели с приятели: |