Разработка функциональных замыканий с помощью наследования
На языке С# функциональное замыкание может быть реализовано несколькими способами. Первый способ - через наследование. Идея состоит в том, чтобы иметь базовый класс, "знающий" о функциональных замыканиях, и производный класс, выполняющий конкретную работу внутри замыкания. В качестве примера рассмотрим класс для отображения всплывающего окна. Создание абстрактного базового класса является здесь хорошей отправной точкой.
сlass Popup // абстрактный класс
{
Image region; //Область занимаемая окном
public:
Popup(Rectangle r)
{ /* сохранение координат и размеров открываемого всплывающего окна */};
virtual void Display(Graphics g)=0;
~Popup(){/* восстановление закрытой области */};
}
Если для отображения реального всплывающего окна породить класс от Popup, то компилятор автоматически будет вызывать конструктор и деструктор базового класса, которые сыграют роль вступления и заключения функционального замыкания.
class SetupPopupWindow: Popup
{
public:
SetupPopupWindow(): Popup(1, 10, 100, 100){ /* построение содержимого окна */ };
void Display()
{
// реализация функции базового класса для запоминания области экрана,
// занимаемой данным окном, и рисование самого окна
};
// Вызов деструктора базового класса, который восстановит изображение
// области экрана, закрытой окном
}
// использование всплывающего окна
main()
{
SetupPopupWindow help;
help.Display();
// …
};
Всякий раз, при создании объекта класса SetupPopupWindow, детали сохранения и восстановления экрана обрабатываются компилятором. Подобная процедура хорошо работает тогда, когда необходимо функциональное замыкание в специализированном классе, полученном через наследование. С помощью наследуемых функциональных замыканий можно решить много задач, но не все.
Разработка функциональных замыканий с помощью экземпляров класса
Альтернативный способ создания функциональных замыканий с помощью экземпляров класса заключается в использовании динамики создания объекта при выполнении программы. Это проще наследования, но имеет свои ограничения. Здесь, как и в технологии с использованием наследования, используется автоматический вызов конструкторов и деструкторов. При создании экземпляра класса компилятор вызывает конструктор класса. Когда экземпляр разрушается, то компилятор вызывает деструктор класса. Конструктор и деструктор могут вновь сыграть роль вступления и заключения. И действительно, конструктор отводит ресурсы, функции - члены манипулируют ими, а деструктор освобождает их. Поскольку компилятор гарантирует обязательный вызов деструктора при разрушении объекта, то можете быть уверены в том, что ресурсы не будут по ошибке "болтаться" в системе.
Рассмотрим следующую реализацию всплывающего окна.
class Popup
{
Rectangle region;
public:
Popup(Rectangle r){ /* сохранение области экрана закрываемое окном */ };
...
~Popup(){ /* восстановление закрытой области */ };
}
// использование всплывающего окна
main()
{
Popup window;
// …
}
Функциональные замыкания являются очень важным элементом системы обработки исключительных ситуаций в языке С#. Если во время выполнения программы возникает исключительная ситуация, то программа переходит за пределы локальной области видимости. В результате, система автоматически вызывает деструкторы для тех объектов, которые, в результате перехода, выходят из области видимости. Не используя надлежащим образом концепцию функционального замыкания, можно легко ввести ошибки в свою программу.