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

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

Iterator Iterator – Problém struct Item { int _value; Item * _next; Item( int value, Item * next ) : _value( value ), _next( next ) { } }; void Print(

Podobné prezentace


Prezentace na téma: "Iterator Iterator – Problém struct Item { int _value; Item * _next; Item( int value, Item * next ) : _value( value ), _next( next ) { } }; void Print("— Transkript prezentace:

1

2 Iterator

3 Iterator – Problém 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ý seznam binární vyhledávací strom Mějme libovolnou kolekci čísel a chceme je všechna vypsat na obrazovku Hlavní podstata řešení úlohy se nemění, ale výrazně se liší okolní kontext, který závisí na zvolené reprezentaci samotné kolekce. Nešlo by to lépe?

4 Iterator – Použití a výhody Co je tedy hlavním přínosem iterátoru?  dává nám snadný způsob, jak sekvenčně přistupovat k prvkům kolekce, a to bez nutnosti odhalovat její interní reprezentaci  uživatel iterátoru se tak nemusí zatěžovat složitým principem fungování kolekce a může se zaměřit jen a pouze na úkol, který s její pomocí řeší A jaké jsou další výhody?  zjednodušení rozhraní kolekce  odlišné způsoby iterace nad kolekcí  více současných iterací nad jednou kolekcí  jednotné rozhraní pro iterování nad kolekcemi  záměna kolekcí beze změny uživatelského kódu

5 Iterator – Základní forma Základní princip  jednoznačné spárování iterátoru s danou kolekcí  zodpovědnost za přístup k prvkům kolekce přenesena na iterátor  k tomuto účelu definuje iterátor vhodné rozhraní  iterátor samotný udržuje informaci o právě vybraném prvku a 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é  není součástí návrhového vzoru  prostor pro různé užitečné operace

6 Iterator – Základní forma - použití Příklad použití rozhraní iterátoru  výpis jmen zaměstnanců z kolekce vybraných iterátorem 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(); } Jeden uživatelský kód, ale různé varianty  všichni  jen ti, kteří splňují určitou podmínku  v obráceném sledu

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;

10 Iterator – Příklad implementace 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 ) { } };

11 Iterator – Užití vzoru Proxy Důsledkem užití vzoru Factory Method jsou dynamicky alokované iterátory  je tedy otázkou, kdo by je měl dealokovat  zřejmě uživatel, ten je ale nezodpovědný a hrozí tak úniky paměti Třída pracující ve smyslu návrhového vzoru Proxy tento problém řeší  „obaluje“ iterátor a sama se později postará o jeho destrukci  její instance jsou vytvářeny na zásobníku template class IteratorPtr { public: IteratorPtr( Iterator * it ) : _it( it ) { } ~IteratorPtr() { delete _it; } Iterator * operator->() { return _it; } Iterator & operator*() { return *_it; } private: Iterator * _it; IteratorPtr( const IteratorPtr & ); IteratorPtr & operator=( const IteratorPtr & ); }; AbstractList * employees; //... Iterator * it = employees->CreateIterator(); PrintEmployees( *it ); delete it; AbstractList * employees; //... IteratorPtr it( employees->CreateIterator()); PrintEmployees( *it ); // Na konci bloku je automaticky // zavolán destruktor IteratorPtr, // a dojde k dealokaci iterátoru.

12 Iterator – Rozdělení Podle toho, kdo řídí průběh iterace:  externí iterátor  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  interní iterátor  naopak řízení iterace obstarává přímo iterátor  a uživatel pouze specifikuje, co má iterátor s prvky vykonat  užitečné především v jazycích s podporou lambda funkcí  pro některé typy operací se však vyloženě nehodí Podle toho, kdo implementuje algoritmus iterace nad kolekcí:  iterátor  určitě 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  v takovém případě mluvíme o tzv. variantě Cursor

13 Iterator – Otázky Jaké je chování při modifikacích kolekce během iterování?  typicky nebezpečná a nepodporovaná operace  lze řešit iterací nad kopií kolekce nebo robustnějším iterátorem Jak řešit okrajové podmínky bez speciálních ošetření?  pomůže „degenerovaná“ varianta – tzv. Null iterátor  z definice je vždy na konci kolekce a neukazuje na žádný prvek  metoda IsDone() tedy vždy vrací hodnotu true Nad čím vším můžeme iterovat?  cokoliv nás napadne, fantazii se meze nekladou  lze např. realizovat „nekonečný“ iterátor  pro proudová data načítána z externího zdroje  nebo pro číselné posloupnosti (Fibonacciho aj.)  iterování napříč XML dokumentem  nebo nad adresářovou strukturou ……

14 Iterator – Zapouzdření Iterátor je velmi úzce spojen se svou kolekcí  pokud je algoritmus iterace nad kolekcí umístěn v iterátoru (externí iterátor), tak typicky potřebuje přistupovat k vnitřní struktuře kolekce, a to nad rámec jejího veřejného rozhraní  dochází tak „narušení“ zapouzdření třídy kolekce  v C++ lze k vyjádření tohoto vztahu použít konstrukci friend  v Javě lze stejného efektu docílit modifikátorem protected v rámci stejného package Přidání nového typu iterátoru však může být obtížné  díky potřebě přidat nový iterátor jako friend třídu kolekce  řešením je friend nadtřída všech iterátorů, která bude poskytovat protected metody, jenž budou „rozšiřovat“ rozhraní kolekce pro potřeby iterátorů

15 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 ) { //... } //... };

16 Iterator – Shrnutí na závěr Klíčové momenty  polymorfní iterátor  instance vytvářeny pomocí Factory Method  a spravovány pomocí Proxy  kolekce má jako friend třídu abstraktního předka iterátorů  externí vs. interní iterátory – podle volby umístění řízení iterace  normální vs. Cursor – podle volby umístění algoritmu 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  mimo jiné i na pozadí různých „foreach“ konstrukcí Jaké jsou související návrhové vzory?  Factory Method  Proxy  Composite – iterace nad rekurzivní strukturou  Memento – zachytávání stavu iterace


Stáhnout ppt "Iterator Iterator – Problém struct Item { int _value; Item * _next; Item( int value, Item * next ) : _value( value ), _next( next ) { } }; void Print("

Podobné prezentace


Reklamy Google