Мне было интересно, что же делает Итератор особенным по сравнению с другими подобными конструкциями, и это заставило Банду Четырех перечислить его как шаблон проектирования.
Итератор основан на полиморфизме (иерархия коллекций с общим интерфейсом) и разделении задач (итерации по коллекциям должны быть независимы от структуры данных).
Но что, если мы заменим иерархию коллекций, например, иерархией математических объектов (целое число, число с плавающей запятой, комплекс, матрица и т. Д.), А итератор - классом, представляющим некоторые связанные операции над этими объектами, например, степенные функции. Диаграмма классов будет такой же.
Возможно, мы могли бы найти еще много похожих примеров, таких как Writer, Painter, Encoder и, возможно, лучших, которые работают одинаково. Однако я никогда не слышал, чтобы кто-либо из них назывался Design Pattern.
Так что же делает Итератор особенным?
Является ли тот факт, что это сложнее, потому что он требует изменяемого состояния для хранения текущей позиции в коллекции? Но тогда изменчивое состояние обычно не считается желательным.
Чтобы прояснить мою точку зрения, позвольте мне привести более подробный пример.
Вот наша проблема дизайна:
Допустим, у нас есть иерархия классов и операция, определенная для объектов этих классов. Интерфейс этой операции одинаков для каждого класса, но реализации могут быть совершенно разными. Также предполагается, что имеет смысл применять операцию несколько раз к одному и тому же объекту, скажем, с разными параметрами.
Вот разумное решение для нашей проблемы проектирования (практически обобщение шаблона итератора):
Для разделения задач реализации операции не следует добавлять как функции к исходной иерархии классов (объекты операндов). Поскольку мы хотим применить операцию несколько раз к одному и тому же операнду, она должна быть представлена объектом, содержащим ссылку на операнд, а не просто функцией. Поэтому объект операнда должен предоставлять функцию, которая возвращает объект, представляющий операцию. Этот объект предоставляет функцию, которая выполняет фактическую операцию.
Пример:
Есть базовый класс или интерфейс MathObject
(глупое имя, я знаю, может, у кого-то есть идея получше) с производными классами MyInteger
и MyMatrix
. Для каждого должна быть определена MathObject
операция Power
, которая позволяет вычислять квадрат, куб и так далее. Таким образом, мы могли бы написать (на Java):
MathObject i = new MyInteger(5);
Power powerOfFive = i.getPower();
MyInteger square = powerOfFive.calculate(2); // should return 25
MyInteger cube = powerOfFive.calculate(3); // should return 125