Проекты Логинова Дмитрия | ||||||||||
|
Справочная система
Программирование внешних функцийВнешними функциями будем называть все подпрограммы, находящиеся вне модуля Matrix.pas. Такие функции отличаются тем, что в них среди входных параметров обязательно присутствует ссылка на рабочую область, содержащую входные массивы. Внешние функции могут быть двух видов: Функции первого типа во время работы создают временную рабочую область, в которую передаются все входные массивы под определенными именами, после чего обработка массивов выполняется независимо от других рабочих областей. В конце работы такая функция возвращает результаты (выходные массивы) в родительскую рабочую область, после чего рабочая область внешней функции уничтожается. Функции второго типа не создают собственной рабочей областью, а используют рабочую область, указанную в параметрах. К преимуществам функций данного типа следует отнести несколько более высокую скорость обработки, что связано с отсутствием необходимости выполнять создание рабочей области и осуществлять обмен массивами. Недостатком таких функций является неудобство работы с ними: приходится придерживаться уникальности имен массивов, вследствие чего имена всех временно создаваемых функцией массивов должны быть сгенерированы с помощью функции GenName(), а в конце работы функции все временные массивы должны быть удалены. При работе с функциями первого типа таких проблем не возникает. Рассмотрим правила программирования внешних функций с собственной рабочей областью.
Создадим простейшую внешнюю функцию, которая складывает два массива 'A' и 'B' и умножает результат сложения на третий массив 'C'. На выходе функции формируется массив 'D'. procedure ExternalFunc(Ws: TWorkspace; A, B, C, D: string); begin with TWorkspace.Create('Внешная функция', Ws) do begin // Проверка правильности имени выходного массива CheckResAr(D); LoadArray(A, 'A'); // Передача ссылки на массив А LoadArray(B, 'B'); // Передача ссылки на массив В LoadArray(C, 'C'); // Передача ссылки на массив С CalcFunc2('A', 'B', 'Tmp', fncSum); // A + B = Tmp CalcFunc2('Tmp', 'C', 'D', fncMul); // Tmp * C = D // Предыдущие две строки можно свернуть в одну, // как показано ниже: // CalcFunc2(CalcFunc2('A', 'B', 'Tmp', fncSum), // 'C', 'D', fncMul); // Возвращаем массив D ReturnArray('D', D); // Уничтожаем рабочую область Free; end; end; В первой строке находится заголовок подпрограммы. Параметры A, B и С соответствуют входным массивам, параметр D соответствует выходному массиву, Ws - ссылка на рабочую область. Именно рабочая область Ws содержит все входные массивы и в нее же необходимо передать полученный выходной массив 'D'. Комментарии подробно раскрывают смысл каждой строки текста. В самом начале процедуры происходит создание рабочей области. Оператор with позволяет не объявлять переменную класса TWorkspace. Если в вашей подпрограмме должна вызываться другая подпрограмма, то в качестве ссылки на рабочую область достаточно передать указатель SelfWS. Сформулируем несколько правил, которых желательно придерживаться для того, чтобы программируемые вами функции были максимально простыми, понятными и быстрыми.
Рассмотрим правила программирования внешних функций без выделенной рабочей области. Будем использовать тот же пример (D=(A+B)*C). Ниже представлен листинг процедуры: procedure ExternalFunc1(Ws: TWorkspace; A, B, C, D: string); var Tmp: string; begin with Ws do begin // Генерируем исключение при отсутствии одного из массивов if (not ArrayExists(A)) or (not ArrayExists(B)) or (not ArrayExists(C)) then DoError(matArrayNotFound); CheckResAr(D); // Проверяем имя выходного массива Tmp := GenName(); // Генерируем имя временного массива CalcFunc2(CalcFunc2('A', 'B', Tmp, fncSum), 'C', Tmp, fncMul); RenameArray(Tmp, D); // Переименовываем временный массив end; end; Хотя код должен работать немного быстрее, однако приходится выполнять некоторые неудобные дополнительные действия:
На самом деле необходимость удаления временных массивов - достаточно существенный недостаток внешних функций без выделенной рабочей области. Дело в том, что в ходе работы функции иногда приходится работать с десятками временных массивов, причем бывают ситуации, когда количество выходных массивов больше одного. Мало того, что для каждого временного массива приходится объявлять строковую переменную и вызывать функцию GenName(), но нужно еще вовремя удалять ненужные временные массивы. Таких проблем в функциях с выделенной рабочей областью не возникает по определению. Преимущество внешних функций без выделенной рабочей области - более высокая скорость работы, т.к. нет необходимости инициализировать дополнительную рабочую область и выполнять обмен данными. Программист сам должен решить, как нужно реализовать конкретную подпрограмму, однако в большинстве случаев используются временная рабочая область. | |||||||||
Логинов Дмитрий © 2005-2015 |