10.1 Обратные вызовы

Предыдущая  Содержание  Следующая V*D*V

Объект указывает на его описание класса. Описание класса указывает на все динамически компонуемые методы, применимые к данному объекту. Выглядит так, как будто нам необходимо спрашивать объект, может ли он отреагировать на определённый метод. В некотором роде это защитная мера: во время выполнения можно проверять сомнительный объект, действительно ли разрешено применять к нему определённый метод. Если не проверим, селектор метода, конечно, проверит и порушит программу, если объект не может ответить, то есть если описание класса объекта не содержит требуемый метод.

Почему мы действительно хотели бы это знать? Мы неудачники, если метод обязательно должен быть применён к объекту, который не знает об этом; поэтому, нет никакой потребности проверять. Однако, если для нашего собственного алгоритма не имеет никакого значения, может ли быть применён данный метод, или нет, способность узнать это делает интерфейс более прощающим.

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

Регистрация функции обратного вызова, первый метод, похож на более гибкий подход. Клиент регистрирует функции только для тех событий, которые важны с его точки зрения. Различные клиенты могут использовать различные наборы функций обратного вызова и нет никакой потребности соблюдать общее пространство имён. ANSI-C на самом деле использует некоторые функции обратного вызова: bsearch() и qsort() получают функцию сравнения, используя которую ищут и сортируют, а atexit() регистрирует  функции, которые вызываются непосредственно перед тем, как программа завершается.

Достижение соглашения об определённых именах функций выглядит ещё проще: распознаватель, сгенерированный lex, вызовет функцию yywrap() в конце входного файла и продолжит обработку, если эта функция не возвратит ноль. Конечно, непрактично, если требуется более, чем одна такая функция в программе. Если бы bsearch() предполагала, что функция сравнения называется cmp, это было бы намного менее гибко.

 

Предыдущая  Содержание  Следующая