// The collection interface must declare a factory method for // producing iterators. You can declare several methods if there // are different kinds of iteration available in your program. interfaceSocialNetwork is method createFriendsIterator(profileId):ProfileIterator method createCoworkersIterator(profileId):ProfileIterator
// Each concrete collection is coupled to a set of concrete // iterator classes it returns. But the client isn't, since the // signature of these methods returns iterator interfaces. classFacebookimplementsSocialNetwork is // ... The bulk of the collection's code should go here ...
// Iterator creation code. method createFriendsIterator(profileId) is returnnewFacebookIterator(this, profileId, "friends") method createCoworkersIterator(profileId) is returnnewFacebookIterator(this, profileId, "coworkers")
// The common interface for all iterators. interfaceProfileIterator is method getNext():Profile method hasMore():bool
// The concrete iterator class. classFacebookIteratorimplementsProfileIterator is // The iterator needs a reference to the collection that it // traverses. private field facebook: Facebook private field profileId, type: string
// An iterator object traverses the collection independently // from other iterators. Therefore it has to store the // iteration state. private field currentPosition private field cache: array of Profile
constructor FacebookIterator(facebook, profileId, type) is this.facebook = facebook this.profileId = profileId this.type = type
// Each concrete iterator class has its own implementation // of the common iterator interface. method getNext() is if(hasMore()) result = cache[currentPosition] currentPosition++ return result
method hasMore() is lazyInit() return currentPosition < cache.length
// Here is another useful trick: you can pass an iterator to a // client class instead of giving it access to a whole // collection. This way, you don't expose the collection to the // client. // // And there's another benefit: you can change the way the // client works with the collection at runtime by passing it a // different iterator. This is possible because the client code // isn't coupled to concrete iterator classes. classSocialSpammer is method send(iterator: ProfileIterator, message: string) is while(iterator.hasMore()) profile = iterator.getNext() System.sendEmail(profile.getEmail(), message)
// The application class configures collections and iterators // and then passes them to the client code. classApplication is field network: SocialNetwork field spammer: SocialSpammer
method config() is if working with Facebook this.network = newFacebook() if working with LinkedIn this.network = newLinkedIn() this.spammer = newSocialSpammer()
method sendSpamToFriends(profile)is iterator= network.createFriendsIterator(profile.getId()) spammer.send(iterator, "Very important message")
method sendSpamToCoworkers(profile)is iterator= network.createCoworkersIterator(profile.getId()) spammer.send(iterator, "Very important message")
from __future__ import annotations from collections.abc import Iterable, Iterator from typing importAny
""" To create an iterator in Python, there are two abstract classes from the built- in `collections` module - Iterable,Iterator. We need to implement the `__iter__()` method in the iterated object (collection), and the `__next__ ()` method in theiterator. """
classAlphabeticalOrderIterator(Iterator): """ Concrete Iterators implement various traversal algorithms. These classes store the current traversal position at all times. """
""" `_position` attribute stores the current traversal position. An iterator may have a lot of other fields for storing iteration state, especially when it is supposed to work with a particular kind of collection. """ _position: int = None
""" This attribute indicates the traversal direction. """ _reverse: bool = False
def__next__(self) -> Any: """ The __next__() method must return the next item in the sequence. On reaching the end, and in subsequent calls, it must raise StopIteration. """ try: value = self._collection[self._position] self._position += -1if self._reverse else1 except IndexError: raise StopIteration()
return value
classWordsCollection(Iterable): """ Concrete Collections provide one or several methods for retrieving fresh iterator instances, compatible with the collection class. """
def__iter__(self) -> AlphabeticalOrderIterator: """ The __iter__() method returns the iterator object itself, by default we return the iterator in ascending order. """ return AlphabeticalOrderIterator(self)
if __name__ == "__main__": # The client code may or may not know about the Concrete Iterator or # Collection classes, depending on the level of indirection you want to keep # in your program. collection = WordsCollection() collection.add_item("First") collection.add_item("Second") collection.add_item("Third")
/// A custom collection contains an arbitrary user array under the hood. implUserCollection { /// Returns a custom user collection. pubfnnew() ->Self { Self { users: ["Alice", "Bob", "Carl"], } }
/// Returns an iterator over a user collection. /// /// The method name may be different, however, `iter` is used as a de facto /// standard in a Rust naming convention. pubfniter(&self) -> UserIterator { UserIterator { index: 0, user_collection: self, } } }
/// UserIterator allows sequential traversal through a complex user collection /// without exposing its internal details. pubstructUserIterator<'a> { index: usize, user_collection: &'a UserCollection, }
/// `Iterator` is a standard interface for dealing with iterators /// from the Rust standard library. implIteratorforUserIterator<'_> { typeItem = &'staticstr;
/// A `next` method is the only `Iterator` trait method which is mandatory to be /// implemented. It makes accessible a huge range of standard methods, /// e.g. `fold`, `map`, `for_each`. fnnext(&mutself) ->Option<Self::Item> { ifself.index < self.user_collection.users.len() { letuser = Some(self.user_collection.users[self.index]); self.index += 1; return user; }