Prezentace se nahrává, počkejte prosím

Prezentace se nahrává, počkejte prosím

Iterator. C historie int * rand_numbers(int n) { int *numbers = malloc(n * sizeof(int)); int *it = numbers; while (it < numbers + n) *it++ = rand(); //

Podobné prezentace


Prezentace na téma: "Iterator. C historie int * rand_numbers(int n) { int *numbers = malloc(n * sizeof(int)); int *it = numbers; while (it < numbers + n) *it++ = rand(); //"— Transkript prezentace:

1 Iterator

2 C historie int * rand_numbers(int n) { int *numbers = malloc(n * sizeof(int)); int *it = numbers; while (it < numbers + n) *it++ = rand(); // vlastně jsem chtěl vygenerovat 2n čísel numbers = realloc(numbers, 2 * n * sizeof(int)); // it = numbers + n; while (it < numbers + (2 * n)) *it++ = rand(); return numbers; } Nejjednodušší formou iterátoru je ukazatel  inkrementace ukazatele znamená posun iterátoru Objekt nebo jeho kritická část nesmí ukazateli za zády zmizet  "vetchý" iterátor  programátoři implicitně chápou takové chování  rys vlastní většině iterátorů dodnes

3 Iterator – Motivace struct Item { int _value; Item * _next; Item( int value, Item * next ) : _value( value ), _next( next ) { } }; void Print( Item * list ) { for( Item * item = list; item != 0; item = item->_next){ std::cout _value << std::endl; } struct Node { int _value; Node * _left; Node * _right; Node( int value, Node * left, Node * right ) : _value( value ), _left( left ), _right( right ) { } }; void Print( Node * tree ) { if (tree != 0) { Node * node = tree; Print( node->_left ); std::cout _value << std::endl; Print( node->_right ); } lineární spojový seznambinární vyhledávací strom Mějme kolekci čísel kterou chceme celou vypsat na obrazovku Implementace libovolné funkce závisí na konkrétní kolekci Co když chceme napsat knihovnu použitelnou s libovolnou kolekcí?

4 Iterator – Cíl, použití a výhody Knihovna kolekcí  uživatel kolekce se nemusí zatěžovat složitým principem fungování kolekce  může se zaměřit jen na úkol, který řeší  pokud mu stačí sekvenční přístup Další výhody  zjednodušení rozhraní kolekce  odlišné způsoby iterace nad kolekcí  více současných iterací nad jednou kolekcí  záměna kolekcí beze změny uživatelského kódu Proč iterátor?  chceme snadné a jednotné rozhraní pro sekvenční přistup k prvkům kolekce  bez nutnosti odhalovat její interní reprezentaci Knihovna algoritmů  funkce definované v knihovně nemusí znát konkrétní kolekci, nad kterou pracují  uživatel si může definovat vlastní kolekce do jednoho frame - na všech slajdech tam kde je to vhodné!

5 Iterator – Základní forma Základní principy  jednoznačné spárování iterátoru s kolekcí  zodpovědnost za přístup k prvkům kolekce přenesena na iterátor  iterátor udržuje informaci o aktuálním prvku  je schopen určit prvek následující Rozhraní iterátoru  minimální  inicializace na první prvek  posun na následující prvek  test na konec  získání aktuálního prvku  další možná rozšíření  posun na předchozí prvek  posun na libovolný prvek  … Rozhraní kolekce zůstává jednoduché

6 Iterator – Základní forma - použití Příklad použití rozhraní iterátoru (GoF, C++)  výpis jmen zaměstnanců z kolekce struct Employee { std::string _name; void Print() { std::cout << _name << std::endl; } }; void PrintEmployees( ListIterator & it ) { for ( it.First(); !it.IsDone(); it.Next() ) { it.CurrentItem()->Print(); } Funkce PrintEmployees() je stále svázána s kolekcí List  konkrétní iterátor je vždy svázán s danou kolekcí  nutno využít polymorfismus (rozhraní)

7 Iterator – Polymorfismus obecná rozhraní konkrétní implementace iterátoru konkrétní implementace kolekce

8 Iterator – Polymorfismus Abstraktní kolekce (Aggregate)  rozhraní pro vytváření iterátorů Konkrétní kolekce  vytváří instance konkrétního iterátoru Abstraktní iterátor (Iterator)  rozhraní pro sekvenční iteraci nad kolekcí Konkrétní iterátor  implementace rozhraní iterátoru  udržuje informaci o právě vybraném prvku Factory Method

9 Iterator – Užití vzoru Factory Method Řešení problému, jak vytvářet instance konkrétních iterátorů  abychom mohli psát kód, který je nezávislý na použité konkrétní kolekci Důsledky  jde o „propojení“ obou hierarchií tříd  přináší dynamickou alokaci instancí iterátorů AbstractList employees; //... Iterator * it = employees.CreateIterator(); PrintEmployees( *it ); delete it; unique_ptr > it( employees.CreateIterator()); PrintEmployees( *it ); Iterator it = employees.CreateIterator(); PrintEmployees( it ); C++98 C++11 JAVA

10 Iterator – Příklad implementace (GoF, C++98) template class Iterator { public: virtual void First() = 0; virtual void Next() = 0; virtual bool IsDone() const = 0; virtual Item CurrentItem() const = 0; protected: Iterator(); }; template class AbstractList { public: virtual Iterator * CreateIterator() const = 0; }; template class List : public AbstractList { public: //... long Count() const; Item & Get( long index ) const; //... virtual Iterator * CreateIterator() const { return new ListIterator ( this ); } }; template class ListIterator : public Iterator { protected: const List * _list; long _current; public: virtual void First() { _current = 0; } virtual void Next() { _current++; } virtual bool IsDone() const { return _current >= _list->Count(); } virtual Item CurrentItem() const { if ( !IsDone() ) { return _list->Get( _current ); } else { throw IteratorOutOfBounds; } ListIterator( const List * list ) : _list( list ), _current( 0 ) { } }; unique_ptr<>

11 Iterator – Rozdělení Podle toho, kdo řídí průběh iterace:  externí iterátor (procedurální pohled na iteraci)  uživatel se sám explicitně dotazuje iterátoru na následující prvek kolekce  řízení iterace tak leží výhradně na uživateli  flexibilnější, ale „složitější“ varianta  snadno pochopitelné, přímá analogie s ukazateli  interní iterátor (funkcionální pohled na iteraci)  řízení iterace obstarává přímo iterátor  uživatel pouze specifikuje akce s prvky  užitečné především v jazycích s podporou lambda funkcí  pro některé typy operací se nehodí (např. porovnání dvou kolekcí) Podle toho, kdo implementuje algoritmus iterace nad kolekcí:  iterátor  flexibilnější  jde naproti znovupoužitelnosti kódu  typicky ale „narušuje“ zapouzdření  nebo samotná kolekce  iterátor pouze udržuje aktuální pozici v kolekci  tzv. Cursor (pozor: nejednotná terminologie)

12 Iterator – Otázky Jaké je chování při modifikacích kolekce během iterování?  typicky nebezpečná operace bez možnosti kontroly v čase kompilace  lze řešit iterací nad kopií kolekce nebo robustnějším iterátorem  např. kolekce vede evidenci iterátorů a tyto dle potřeby aktualizuje  Robert B. Murray. C++ Strategies and Tactics. Addison-Wesley, Reading, MA, 1993.  nevýhoda mnoha implementací iterátorů Nad čím vším můžeme iterovat?  cokoliv nás napadne, fantazii se meze nekladou  virtuální nebo „nekonečný“ iterátor  proudová data načítána z externího zdroje  číselné posloupnosti (Fibonacciho aj.), generátor  kolekce je generována iterátorem, prvky nejsou přítomny v paměti  filtr - výběr pouze určitých prvků dle predikátu  XML dokument, adresářová struktura, DB resultset,...,...

13 Iterator – Zapouzdření Iterátor je velmi úzce spojen se svou kolekcí  externí iterátor - potřebuje přistupovat k vnitřní struktuře kolekce  nad rámec veřejného rozhraní  „narušení“ zapouzdření třídy kolekce  C++: konstrukce friend  Java: modifikátor protected v rámci stejné package Přidání nového typu iterátoru může být obtížné  potřeba přidat nový iterátor jako friend třídu kolekce  řešení: friend nadtřída všech iterátorů  poskytuje protected metody, rozšiřující rozhraní kolekce pro potřeby iterátorů

14 Iterator – Zapouzdření class ListIterator : public Iterator { private: List * _list; protected: bool _LstIsOut( Item * item ) { return _list->_IsOut( item ); } Item * _LstGetNext( Item * item ) { return _list->_GetNext( item ); } //... }; class ForwardListIterator : public ListIterator { private: Item * _current; public: bool IsDone() { return _LstIsOut( _current ); } void Next() { _current = _LstGetNext( _current ); } Item CurrentItem() { return *_current; } //... }; class List : public AbstractList { friend class ListIterator; private: bool _IsOut( Item * item ) { //... } Item * _GetNext( Item * item ) { //... } //... }; Item je interně použit jako Cursor

15 Iterator – Shrnutí Klíčové momenty  iterator s jednotným rozhraním  instance vytvářeny pomocí Factory Method  externí vs. interní iterátory – podle volby umístění řízení iterace  normální vs. Cursor – podle volby umístění algoritmu iterace  externí iterátory nebývají odolné vůči změnám kolekce v průběhu iterace Kde se s iterátory setkáme  kolekce v objektově orientovaných jazycích – C++, C#, Java, …  Java poskytuje rozhraní Iterable – třída pouze implementuje  na pozadí konstrukcí „foreach“  posun iterátorů z knihoven do syntaxe jazyků Související návrhové vzory  Factory Method - vytváření iterátorů  Proxy - ochrana syrových ukazatelů, resource management  Composite - iterace nad rekurzivní strukturou  Memento - zachytávání stavu iterace


Stáhnout ppt "Iterator. C historie int * rand_numbers(int n) { int *numbers = malloc(n * sizeof(int)); int *it = numbers; while (it < numbers + n) *it++ = rand(); //"

Podobné prezentace


Reklamy Google