В об'єктно-орієнтованому програмуванні шаблон проектування ітератор — це шаблон проектування, у якому ітератор використовується для обходу колекції та доступу до елементів колекції. Шаблон ітератора відокремлює алгоритми від колекції; у деяких випадках алгоритми обов'язково залежать від колекції і тому не можуть бути відокремлені.
Наприклад, гіпотетичний алгоритм ЗнайтиЕлемент може бути реалізований загалом за допомогою певного типу ітератора, а не реалізований як специфічний для колекції алгоритм. Це дозволяє використовувати ЗнайтиЕлемент у будь-якій колекції, яка підтримує необхідний тип ітератора.
Шаблон проектування Ітератор є одним із двадцяти трьох відомих шаблонів проектування GoF, які описують, як розв'язувати повторювані проблеми проектування для розробки гнучкого та багаторазового об'єктно-орієнтованого програмного забезпечення, тобто об'єктів, які легше реалізувати, змінити, тестування та повторне використання. Належить до класу шаблонів поведінки.
Призначення
Надає спосіб послідовного доступу до всіх елементів складеного об'єкта, не розкриваючи його внутрішнього улаштування.
Мотивація
Складений об'єкт, скажімо список, повинен надавати спосіб доступу до своїх елементів, не розкриваючи їхню внутрішню структуру. Більш того, іноді треба обходити список по-різному, у залежності від задачі, що вирішується. При цьому немає ніякого бажання засмічувати інтерфейс класу Список усілякими операціями для усіх потрібних варіантів обходу, навіть якщо їх усі можна передбачити заздалегідь. Крім того, іноді треба, щоб в один момент часу існувало декілька активних операцій обходу списку.
Все це призводить до необхідності реалізації шаблону Ітератор. Його основна ідея у тому, щоб за доступ до елементів та обхід списку відповідав не сам список, а окремий об'єкт-ітератор. У класі Ітератор означений інтерфейс для доступу до елементів списку. Об'єкт цього класу прослідковує поточний елемент, тобто він володіє інформацією, які з елементів вже відвідувались.
Застосовність
Можна використовувати шаблон Ітератор у випадках:
- для доступу до змісту агрегованих об'єктів не розкриваючи їхнє внутрішнє улаштування;
- для підтримки декількох активних обходів одного й того ж агрегованого об'єкта;
- для подання уніфікованого інтерфейсу з метою обходу різноманітних агрегованих структур (тобто для підтримки поліморфної ітерації).
Структура
- Iterator
- визначає інтерфейс для доступу та обходу елементів
- ConcreteIterator
- реалізує інтерфейс класу Iterator;
- слідкує за поточною позицією під час обходу агрегату;
- Aggregate
- визначає інтерфейс для створення об'єкта-ітератора;
- ConcreteAggregate
- реалізує інтерфейс створення ітератора та повертає екземпляр відповідного класу ConcreteIterator
Відносини
ConcreteIterator відслідковує поточний об'єкт у агрегаті та може вирахувати наступний.
Переваги
- Спільний інтерфейс використання
- Перебір колекції
Недоліки
- Основною проблемою ітераторів є те, що реалізація ітераторів може бути складною
Реалізація
C++
#include <iostream> using namespace std; // вузол, що є частиною списку struct Node { double item; Node* next; Node(double x, Node* link = 0) : item(x), next(link) {} }; // «примітивний» ітератор списку class listIter { private: Node* p; public: listIter() :p(0) {} listIter(Node* ptr) : p(ptr) {} double& operator*() { return p->item; } listIter& operator++() { p = p->next; return *this; } bool operator!=(const listIter& a) { return p != a.p; } }; // інтерфейс колекції, яка підтримує ітератор class List { private: Node * first; Node * last; public: List() { first = last = new Node(0); } ~List() { while (first != last) { Node * victim = first; first = first->next; delete victim; } delete first; } List& add(double el) { last = last->next = new Node(el); return *this; } listIter begin() { return listIter(first->next); } listIter end() { return listIter(); } }; void main() { List list; list.add(4).add(2); listIter iter = list.begin(); while (iter != list.end()) { cout << *iter; ++iter; } for (listIter iter2 = list.begin(); iter2 != list.end(); ++iter2) { cout << *iter2; } }
Але щоб ітератор працював із стандартними алгоритмами, варто унаслідувати його від стандартних:
class Iterator : public iterator<bidirectional_iterator_tag,double>
C#
В мові програмування C# шаблон ітератор є вбудованим, його використання можливе за допомогою оператору foreach, за умови, що відповідна колекція реалізує інтерфейс IEnumerable.
Наприклад:
string[] strings = new string[] { "one", "two", "three" }; foreach (string str in strings) { Console.WriteLine(str); }
Таку форму запису можна замінити на більш низько-рівневу, але еквівалентну:
string[] strings = new string[] { "one", "two", "three" }; IEnumerator enumerator = strings.GetEnumerator(); while (enumerator.MoveNext()) { Console.WriteLine((string)enumerator.Current); }
using System; using System.Linq; using System.Collections; using System.Collections.Generic; namespace IteratorPattern { public class Tree : IEnumerable<int> { private class Node { public int Value { get; set; } public Node Left { get; set; } public Node Right { get; set; } } private Node _root; public Tree Add(int value) { _root = AddInternal(value, _root); return this; } private Node AddInternal(int value, Node node) { if (node == null) { node = new Node { Value = value }; } else if (value > node.Value) { node.Right = AddInternal(value, node.Right); } else if (value < node.Value) { node.Left = AddInternal(value, node.Left); } return node; } // приклад реалізації за допомогою блока ітератора // (вбудована можливість мови програмування) #region Inbuilt public IEnumerator<int> GetEnumerator() { return IterateInOrder(_root).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private IEnumerable<int> IterateInOrder(Node node) { if (node == null) yield break; // ARB foreach (var l in IterateInOrder(node.Left)) yield return l; yield return node.Value; foreach (var r in IterateInOrder(node.Right)) yield return r; } #endregion // приклад реалізації ітератора на даній платформі #region Net public BreadthFirstIterator GetBreadthFirstIterator() => new BreadthFirstIterator(this); public class BreadthFirstIterator // : IEnumerator<int> { private readonly Tree _tree; private Node _currentNode; private Queue<Node> _nodeQueue; public int Current => _currentNode.Value; public BreadthFirstIterator(Tree tree) { _tree = tree; Reset(); } public bool MoveNext() { if (!_nodeQueue.Any()) return false; _currentNode = _nodeQueue.Dequeue(); if (_currentNode.Left != null) _nodeQueue.Enqueue(_currentNode.Left); if (_currentNode.Right != null) _nodeQueue.Enqueue(_currentNode.Right); return true; } public void Reset() { _nodeQueue = new Queue<Node>(capacity: 3); _nodeQueue.Enqueue(_tree._root); } } #endregion // класичний приклад реалізації ітератора #region Classic public DepthFirstIterator GetDepthFirstIterator() => new DepthFirstIterator(this); public class DepthFirstIterator // можлива реалізація загального інтерфейсу { private readonly Stack<Node> _nodeStack; public int Current => _nodeStack.Peek().Value; public DepthFirstIterator(Tree tree) { _nodeStack = new Stack<Node>(capacity: 3); _nodeStack.Push(tree._root); } public void Next() { var currentNode = _nodeStack.Pop(); if (currentNode.Left != null) _nodeStack.Push(currentNode.Left); if (currentNode.Right != null) _nodeStack.Push(currentNode.Right); } public bool HasNext() { return _nodeStack.Any(); } } #endregion } class Program { static void Main(string[] args) { // 5 // / \ // 2 8 // / \ // 1 3 var tree = new Tree(); tree.Add(5).Add(2).Add(8).Add(1).Add(3); Console.WriteLine("Inbuilt iterator (yield return)"); // foreach (var v in tree) Console.WriteLine(v); var enumerator = tree.GetEnumerator(); while (enumerator.MoveNext()) { Console.WriteLine(enumerator.Current); } Console.WriteLine("Breadth first iterator (Net version)"); var iterator = tree.GetBreadthFirstIterator(); while (iterator.MoveNext()) { Console.WriteLine(iterator.Current); } Console.WriteLine("Depth first iterator (classic)"); for (var i = tree.GetDepthFirstIterator(); i.HasNext(); i.Next()) { Console.WriteLine(i.Current); } } } }
Python
Python визначає синтаксис для ітераторів як частину самої мови, так що ключові слова мови, такі як for
, працюють з тим, що Python називає ітераторами. Ітератор має метод __iter__()
, який повертає об'єкт ітератора. «Протокол ітератора» вимагає, щоб next()
повернув наступний елемент або викликав виключення StopIteration
після досягнення кінця послідовності елементів ітератора. Ітератори також надають метод __iter__()
, який повертає себе, щоб їх також можна було повторити; наприклад, за допомогою циклу for
. Генератори доступні з версії 2.2.
У Python 3 next()
було перейменовано на __next__()
.
Див. також
Примітки
- Erich Gamma; Richard Helm; Ralph Johnson; John Vlissides (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison Wesley. с. 257ff. ISBN .
- Python v2.7.1 documentation: The Python Standard Library: 5. Built-in Types. Процитовано 2 травня 2011.
Джерела
- Design Patterns: Elements of Reusable Object-Oriented Software [ 9 листопада 2012 у Wayback Machine.]
- Ітерація об'єктів у PHP
- Шаблон ітератора в C#
- Навчальний посібник із SourceMaking
- Шаблон ітератора
Література
Алан Шаллоуей, Джеймс Р. Тротт. Шаблоны проектирования. Новый подход к объектно-ориентированному анализу и проектированию = Design Patterns Explained: A New Perspective on Object-Oriented Design. — М. : «Вильямс», 2002. — 288 с. — .
Вікіпедія, Українська, Україна, книга, книги, бібліотека, стаття, читати, завантажити, безкоштовно, безкоштовно завантажити, mp3, відео, mp4, 3gp, jpg, jpeg, gif, png, малюнок, музика, пісня, фільм, книга, гра, ігри, мобільний, телефон, android, ios, apple, мобільний телефон, samsung, iphone, xiomi, xiaomi, redmi, honor, oppo, nokia, sonya, mi, ПК, web, Інтернет
U Vikipediyi ye statti pro inshi znachennya cogo termina Iterator znachennya V ob yektno oriyentovanomu programuvanni shablon proektuvannya iterator ce shablon proektuvannya u yakomu iterator vikoristovuyetsya dlya obhodu kolekciyi ta dostupu do elementiv kolekciyi Shablon iteratora vidokremlyuye algoritmi vid kolekciyi u deyakih vipadkah algoritmi obov yazkovo zalezhat vid kolekciyi i tomu ne mozhut buti vidokremleni Napriklad gipotetichnij algoritm ZnajtiElement mozhe buti realizovanij zagalom za dopomogoyu pevnogo tipu iteratora a ne realizovanij yak specifichnij dlya kolekciyi algoritm Ce dozvolyaye vikoristovuvati ZnajtiElement u bud yakij kolekciyi yaka pidtrimuye neobhidnij tip iteratora Shablon proektuvannya Iterator ye odnim iz dvadcyati troh vidomih shabloniv proektuvannya GoF yaki opisuyut yak rozv yazuvati povtoryuvani problemi proektuvannya dlya rozrobki gnuchkogo ta bagatorazovogo ob yektno oriyentovanogo programnogo zabezpechennya tobto ob yektiv yaki legshe realizuvati zminiti testuvannya ta povtorne vikoristannya Nalezhit do klasu shabloniv povedinki PriznachennyaNadaye sposib poslidovnogo dostupu do vsih elementiv skladenogo ob yekta ne rozkrivayuchi jogo vnutrishnogo ulashtuvannya MotivaciyaSkladenij ob yekt skazhimo spisok povinen nadavati sposib dostupu do svoyih elementiv ne rozkrivayuchi yihnyu vnutrishnyu strukturu Bilsh togo inodi treba obhoditi spisok po riznomu u zalezhnosti vid zadachi sho virishuyetsya Pri comu nemaye niyakogo bazhannya zasmichuvati interfejs klasu Spisok usilyakimi operaciyami dlya usih potribnih variantiv obhodu navit yaksho yih usi mozhna peredbachiti zazdalegid Krim togo inodi treba shob v odin moment chasu isnuvalo dekilka aktivnih operacij obhodu spisku Vse ce prizvodit do neobhidnosti realizaciyi shablonu Iterator Jogo osnovna ideya u tomu shob za dostup do elementiv ta obhid spisku vidpovidav ne sam spisok a okremij ob yekt iterator U klasi Iterator oznachenij interfejs dlya dostupu do elementiv spisku Ob yekt cogo klasu proslidkovuye potochnij element tobto vin volodiye informaciyeyu yaki z elementiv vzhe vidviduvalis ZastosovnistMozhna vikoristovuvati shablon Iterator u vipadkah dlya dostupu do zmistu agregovanih ob yektiv ne rozkrivayuchi yihnye vnutrishnye ulashtuvannya dlya pidtrimki dekilkoh aktivnih obhodiv odnogo j togo zh agregovanogo ob yekta dlya podannya unifikovanogo interfejsu z metoyu obhodu riznomanitnih agregovanih struktur tobto dlya pidtrimki polimorfnoyi iteraciyi StrukturaUML diagrama sho opisuye strukturu shablonu proyektuvannya Iterator Iterator viznachaye interfejs dlya dostupu ta obhodu elementiv ConcreteIterator realizuye interfejs klasu Iterator slidkuye za potochnoyu poziciyeyu pid chas obhodu agregatu Aggregate viznachaye interfejs dlya stvorennya ob yekta iteratora ConcreteAggregate realizuye interfejs stvorennya iteratora ta povertaye ekzemplyar vidpovidnogo klasu ConcreteIteratorVidnosiniConcreteIterator vidslidkovuye potochnij ob yekt u agregati ta mozhe virahuvati nastupnij PerevagiSpilnij interfejs vikoristannya Perebir kolekciyiNedolikiOsnovnoyu problemoyu iteratoriv ye te sho realizaciya iteratoriv mozhe buti skladnoyuRealizaciyaC Priklad realizaciyi movoyu S include lt iostream gt using namespace std vuzol sho ye chastinoyu spisku struct Node double item Node next Node double x Node link 0 item x next link primitivnij iterator spisku class listIter private Node p public listIter p 0 listIter Node ptr p ptr double amp operator return p gt item listIter amp operator p p gt next return this bool operator const listIter amp a return p a p interfejs kolekciyi yaka pidtrimuye iterator class List private Node first Node last public List first last new Node 0 List while first last Node victim first first first gt next delete victim delete first List amp add double el last last gt next new Node el return this listIter begin return listIter first gt next listIter end return listIter void main List list list add 4 add 2 listIter iter list begin while iter list end cout lt lt iter iter for listIter iter2 list begin iter2 list end iter2 cout lt lt iter2 Ale shob iterator pracyuvav iz standartnimi algoritmami varto unasliduvati jogo vid standartnih class Iterator public iterator lt bidirectional iterator tag double gt C V movi programuvannya C shablon iterator ye vbudovanim jogo vikoristannya mozhlive za dopomogoyu operatoru foreach za umovi sho vidpovidna kolekciya realizuye interfejs IEnumerable Napriklad string strings new string one two three foreach string str in strings Console WriteLine str Taku formu zapisu mozhna zaminiti na bilsh nizko rivnevu ale ekvivalentnu string strings new string one two three IEnumerator enumerator strings GetEnumerator while enumerator MoveNext Console WriteLine string enumerator Current Priklad realizaciyi movoyu S using System using System Linq using System Collections using System Collections Generic namespace IteratorPattern public class Tree IEnumerable lt int gt private class Node public int Value get set public Node Left get set public Node Right get set private Node root public Tree Add int value root AddInternal value root return this private Node AddInternal int value Node node if node null node new Node Value value else if value gt node Value node Right AddInternal value node Right else if value lt node Value node Left AddInternal value node Left return node priklad realizaciyi za dopomogoyu bloka iteratora vbudovana mozhlivist movi programuvannya region Inbuilt public IEnumerator lt int gt GetEnumerator return IterateInOrder root GetEnumerator IEnumerator IEnumerable GetEnumerator return GetEnumerator private IEnumerable lt int gt IterateInOrder Node node if node null yield break ARB foreach var l in IterateInOrder node Left yield return l yield return node Value foreach var r in IterateInOrder node Right yield return r endregion priklad realizaciyi iteratora na danij platformi region Net public BreadthFirstIterator GetBreadthFirstIterator gt new BreadthFirstIterator this public class BreadthFirstIterator IEnumerator lt int gt private readonly Tree tree private Node currentNode private Queue lt Node gt nodeQueue public int Current gt currentNode Value public BreadthFirstIterator Tree tree tree tree Reset public bool MoveNext if nodeQueue Any return false currentNode nodeQueue Dequeue if currentNode Left null nodeQueue Enqueue currentNode Left if currentNode Right null nodeQueue Enqueue currentNode Right return true public void Reset nodeQueue new Queue lt Node gt capacity 3 nodeQueue Enqueue tree root endregion klasichnij priklad realizaciyi iteratora region Classic public DepthFirstIterator GetDepthFirstIterator gt new DepthFirstIterator this public class DepthFirstIterator mozhliva realizaciya zagalnogo interfejsu private readonly Stack lt Node gt nodeStack public int Current gt nodeStack Peek Value public DepthFirstIterator Tree tree nodeStack new Stack lt Node gt capacity 3 nodeStack Push tree root public void Next var currentNode nodeStack Pop if currentNode Left null nodeStack Push currentNode Left if currentNode Right null nodeStack Push currentNode Right public bool HasNext return nodeStack Any endregion class Program static void Main string args 5 2 8 1 3 var tree new Tree tree Add 5 Add 2 Add 8 Add 1 Add 3 Console WriteLine Inbuilt iterator yield return foreach var v in tree Console WriteLine v var enumerator tree GetEnumerator while enumerator MoveNext Console WriteLine enumerator Current Console WriteLine Breadth first iterator Net version var iterator tree GetBreadthFirstIterator while iterator MoveNext Console WriteLine iterator Current Console WriteLine Depth first iterator classic for var i tree GetDepthFirstIterator i HasNext i Next Console WriteLine i Current Python Python viznachaye sintaksis dlya iteratoriv yak chastinu samoyi movi tak sho klyuchovi slova movi taki yak for pracyuyut z tim sho Python nazivaye iteratorami Iterator maye metod iter yakij povertaye ob yekt iteratora Protokol iteratora vimagaye shob next povernuv nastupnij element abo viklikav viklyuchennya StopIteration pislya dosyagnennya kincya poslidovnosti elementiv iteratora Iteratori takozh nadayut metod iter yakij povertaye sebe shob yih takozh mozhna bulo povtoriti napriklad za dopomogoyu ciklu for Generatori dostupni z versiyi 2 2 U Python 3 next bulo perejmenovano na next Div takozhKompozitnij vizerunok Kolekciya struktura danih Shablon proektuvannya informatika Iterator Shablon sposterigachaPrimitkiErich Gamma Richard Helm Ralph Johnson John Vlissides 1994 Design Patterns Elements of Reusable Object Oriented Software Addison Wesley s 257ff ISBN 0 201 63361 2 Python v2 7 1 documentation The Python Standard Library 5 Built in Types Procitovano 2 travnya 2011 DzherelaDesign Patterns Elements of Reusable Object Oriented Software 9 listopada 2012 u Wayback Machine Iteraciya ob yektiv u PHP Shablon iteratora v C Navchalnij posibnik iz SourceMaking Shablon iteratoraLiteraturaAlan Shallouej Dzhejms R Trott Shablony proektirovaniya Novyj podhod k obektno orientirovannomu analizu i proektirovaniyu Design Patterns Explained A New Perspective on Object Oriented Design M Vilyams 2002 288 s ISBN 0 201 71594 5