Блоки — различия между версиями
Korvin (обсуждение | вклад) м (Новая: '''STUB''' Основной идеей при написании как процедурных, так и объектно-ориентированных программ являетс...) |
Версия 20:04, 20 сентября 2007
STUB
Основной идеей при написании как процедурных, так и объектно-ориентированных программ является локализация (заключение) функционала в некоторой области: в функции, либо в методе. Таким образом получается, что программа состоит из множества функционально независимых частей, каждая из которых решает конкретную достаточно узкую задачу. Такой подход позволяет скрыть детали реализации алгоритмов внутри этих частей а "наружу" предоставить только интерфейс - совокупность способов взаимодействия данного функционального элемента с другими. В случае функции, под интерфейсом понимается совокупность ее параметров и возвращаемого значения; в случае классов: наборы методов и свойств.
Случается, что в работе некоторого алгоритма возникают четко определенные функциональные подсистемы, которые, однако, слишком зависимы от самого алгоритма, либо слишком просты для того, чтобы выделять их в отдельную функцию. В случае с C++ это все же приходится делать, даже если эта "минифункция" применяется всего в одном методе, но достаточное количество раз, чтобы программист не захотел копировать эти строки.
В других случаях может возникнуть желание вынести некоторый функционал за пределы текущей функции, или даже предоставить программисту-пользователю возможность самому определить его.
И в том и в другом случае на помощь приходят замыкания, анонимные функции или лямбда функции, как их еще называют. Сущность такой функции в том, что она с одной стороны как бы является переменной, а с другой стороны функцией которую можно вызывать. В К++ такие функции носят название блоков. Сущность переменной блоки проявляют в том, что их можно создавать как локальные переменные, присваивать друг другу и даже передавать другим функциям в качестве параметра. Приняв такой параметр, функция может обратиться к нему как к любой другой функции: вызывать с некоторыми параметрами и как использовать его возвращаемое значение.
Применение блоков
Наиболее подходящая задача, иллюстрирующая идеологию и способы использования блоков — это сортировка элементов массива. Предположим, что программисту требуется реализовать для все того же класса MyCollection механизм сортировки элементов. Под сортировкой в данном случае понимается упорядочивание набора элементов, на основании некоторого критерия, по которому можно судить об их очередности в списке.
Проблема заключается в том, что на этапе написания реализации алгоритма мы не имеем представления о том, какие же элементы будут храниться в коллекции. Как мы отсортируем коллекцию которая может состоять из чего угодно: строк, чисел, массивов и даже экземпляров самого класса MyCollection? Пришлось бы либо писать обширную реализацию некоторого метода сравнения двух элементов, который бы учитывал все возможные варианты типов элементов, либо реализовывать свою функцию сортировки на каждый из типов данных элементов: <source lang="kpp"> extend MyCollection {
public function SortAsNumbers(); public function SortAsStrings(); public function SortAsArrays(); public function SortAsCollections();
} </source>
И тот и другой способ жестко ограничивают функциональность нашего класса коллекции только теми типами элементов, которые были изначально предусмотрены нами. А если программист-пользователь захочет использовать некоторый свой тип данных, или еще проще, захочет сортировать элементы не по возрастанию, а по убыванию? Вероятно, мало кто захочет переписывать все эти функции только для того чтобы изменить порядок сортировки.
Давайте взглянем на проблему шире. В сущности, все вышеописанные методы делают ровно одно и то же: некоторым из алгоритмов сортировки, они упорядочивают элементы в коллекции. При этом, единственная различающаяся часть — это сама операция сравнения двух элементов. Решение напрашивается само собой — необходимо вынести эту часть из самой функции сортировки и предоставить пользователю самому обеспечить операцию сравнения. Таким образом мы получим ОДИН метод сортировки, который будет работать для ЛЮБЫХ типов элементов — программист-пользователь сам укажет необходимый критерий сортировки, который уже будет использован внутри метода.
Эту задачу можно очень красиво решить с помощью блоков: <source lang="kpp"> extend MyCollection {
public function sort(block compare) { /* TODO: код алгоритма сортировки используем compare(x, y) для сравнения */ }
} </source>
В качестве параметра, метод sort() принимает один аргумент — блок, который должен производить сравнение двух элементов и возвращать истину, если требуется их перестановка, то есть они расположены в неправильном порядке.