// 每个具体集合都与其返回的一组具体迭代器相耦合。但客户并不是这样的,因为 // 这些方法的签名将会返回迭代器接口。 class WeChat implements SocialNetwork is // ...大量的集合代码应该放在这里...
// 迭代器创建代码。 method createFriendsIterator(profileId) is return new WeChatIterator(this, profileId, "friends") method createCoworkersIterator(profileId) is return new WeChatIterator(this, profileId, "coworkers")
// 所有迭代器的通用接口。 interface ProfileIterator is method getNext():Profile method hasMore():bool
// 具体迭代器类。 class WeChatIterator implements ProfileIterator is // 迭代器需要一个指向其遍历集合的引用。 private field weChat: WeChat private field profileId, type: string
// 迭代器对象会独立于其他迭代器来对集合进行遍历。因此它必须保存迭代器 // 的状态。 private field currentPosition private field cache: arrayof Profile
method config() is if working with WeChat this.network = new WeChat() if working with LinkedIn this.network = new LinkedIn() this.spammer = new SocialSpammer()
method sendSpamToFriends(profile) is iterator = network.createFriendsIterator(profile.getId()) spammer.send(iterator, "非常重要的消息")
method sendSpamToCoworkers(profile) is iterator = network.createCoworkersIterator(profile.getId()) spammer.send(iterator, "非常重要的消息")
// Returns the key of the current element publicabstractintKey(); // Returns the current element publicabstractobjectCurrent(); // Move forward to next element publicabstractboolMoveNext(); // Rewinds the Iterator to the first element publicabstractvoidReset(); }
abstractclassIteratorAggregate : IEnumerable { // Returns an Iterator or another IteratorAggregate for the implementing // object. publicabstract IEnumerator GetEnumerator(); }
// Concrete Iterators implement various traversal algorithms. These classes // store the current traversal position at all times. classAlphabeticalOrderIterator : Iterator { private WordsCollection _collection; // 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. privateint _position = -1; privatebool _reverse = false;
// Concrete Collections provide one or several methods for retrieving fresh // iterator instances, compatible with the collection class. classWordsCollection : IteratorAggregate { List<string> _collection = new List<string>(); bool _direction = false; publicvoidReverseDirection() { _direction = !_direction; } public List<string> getItems() { return _collection; } publicvoidAddItem(string item) { this._collection.Add(item); } publicoverride IEnumerator GetEnumerator() { returnnew AlphabeticalOrderIterator(this, _direction); } }
classProgram { staticvoidMain(string[] args) { // 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. var collection = new WordsCollection(); collection.AddItem("First"); collection.AddItem("Second"); collection.AddItem("Third");
Console.WriteLine("Straight traversal:");
foreach (var element in collection) { Console.WriteLine(element); }
Console.WriteLine("\nReverse traversal:");
collection.ReverseDirection();
foreach (var element in collection) { Console.WriteLine(element); } } } }
/** * Iterator Design Pattern * * Intent: Lets you traverse elements of a collection without exposing its * underlying representation (list, stack, tree, etc.). */
/** * Generic Collections/Containers provides one or several methods for retrieving * fresh iterator instances, compatible with the collection class. */
classData { public: Data(int a = 0) : m_data_(a) {}
voidset_data(int a){ m_data_ = a; }
intdata(){ return m_data_; }
private: int m_data_; };
/** * The client code may or may not know about the Concrete Iterator or Collection * classes, for this implementation the container is generic so you can used * with an int or with a custom class. */ voidClientCode(){ std::cout << "________________Iterator with int______________________________________" << std::endl; Container<int> cont;
public Profile requestProfileFromFacebook(String profileEmail) { // Here would be a POST request to one of the Facebook API endpoints. // Instead, we emulates long network connection, which you would expect // in the real life... simulateNetworkLatency(); System.out.println("Facebook: Loading profile '" + profileEmail + "' over the network...");
// ...and return test data. return findProfile(profileEmail); }
public List<String> requestProfileFriendsFromFacebook(String profileEmail, String contactType) { // Here would be a POST request to one of the Facebook API endpoints. // Instead, we emulates long network connection, which you would expect // in the real life... simulateNetworkLatency(); System.out.println("Facebook: Loading '" + contactType + "' list of '" + profileEmail + "' over the network...");
// ...and return test data. Profileprofile= findProfile(profileEmail); if (profile != null) { return profile.getContacts(contactType); } returnnull; }
private Profile findProfile(String profileEmail) { for (Profile profile : profiles) { if (profile.getEmail().equals(profileEmail)) { return profile; } } returnnull; }
public Profile requestContactInfoFromLinkedInAPI(String profileEmail) { // Here would be a POST request to one of the LinkedIn API endpoints. // Instead, we emulates long network connection, which you would expect // in the real life... simulateNetworkLatency(); System.out.println("LinkedIn: Loading profile '" + profileEmail + "' over the network...");
// ...and return test data. return findContact(profileEmail); }
public List<String> requestRelatedContactsFromLinkedInAPI(String profileEmail, String contactType) { // Here would be a POST request to one of the LinkedIn API endpoints. // Instead, we emulates long network connection, which you would expect // in the real life. simulateNetworkLatency(); System.out.println("LinkedIn: Loading '" + contactType + "' list of '" + profileEmail + "' over the network...");
// ...and return test data. Profileprofile= findContact(profileEmail); if (profile != null) { return profile.getContacts(contactType); } returnnull; }
private Profile findContact(String profileEmail) { for (Profile profile : contacts) { if (profile.getEmail().equals(profileEmail)) { return profile; } } returnnull; }
SocialSpammerspammer=newSocialSpammer(network); spammer.sendSpamToFriends("anna.smith@bing.com", "Hey! This is Anna's friend Josh. Can you do me a favor and like this post [link]?"); spammer.sendSpamToCoworkers("anna.smith@bing.com", "Hey! This is Anna's boss Jason. Anna told me you would be interested in [link]."); }
Please specify social network to target spam tool (default:Facebook): 1. Facebook 2. LinkedIn > 1
Iterating over friends...
Facebook: Loading 'friends' list of 'anna.smith@bing.com' over the network... Facebook: Loading profile 'mad_max@ya.com' over the network... Sent message to: 'mad_max@ya.com'. Message body: 'Hey! This is Anna's friend Josh. Can you do me a favor and like this post [link]?' Facebook: Loading profile 'catwoman@yahoo.com' over the network... Sent message to: 'catwoman@yahoo.com'. Message body: 'Hey! This is Anna's friend Josh. Can you do me a favor and like this post [link]?'
Iterating over coworkers...
Facebook: Loading 'coworkers' list of 'anna.smith@bing.com' over the network... Facebook: Loading profile 'sam@amazon.com' over the network... Sent message to: 'sam@amazon.com'. Message body: 'Hey! This is Anna's boss Jason. Anna told me you would be interested in [link].'
/** * Concrete Iterators implement various traversal algorithms. These classes * store the current traversal position at all times. */ classAlphabeticalOrderIteratorimplements \Iterator { /** * @var WordsCollection */ private$collection;
/** * @var int 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. */ private$position = 0;
/** * @var bool This variable indicates the traversal direction. */ private$reverse = false;
/** * Concrete Collections provide one or several methods for retrieving fresh * iterator instances, compatible with the collection class. */ classWordsCollectionimplements \IteratorAggregate { private$items = [];
/** * 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 = newWordsCollection(); $collection->addItem("First"); $collection->addItem("Second"); $collection->addItem("Third");
/** * The pointer to the CSV file. * * @var resource */ protected$filePointer = null;
/** * The current element, which is returned on each iteration. * * @var array */ protected$currentElement = null;
/** * The row counter. * * @var int */ protected$rowCounter = null;
/** * The delimiter for the CSV file. * * @var string */ protected$delimiter = null;
/** * The constructor tries to open the CSV file. It throws an exception on * failure. * * @param string $file The CSV file. * @param string $delimiter The delimiter. * * @throws \Exception */ publicfunction__construct($file, $delimiter = ',') { try { $this->filePointer = fopen($file, 'rb'); $this->delimiter = $delimiter; } catch (\Exception$e) { thrownew\Exception('The file "' . $file . '" cannot be read.'); } }
/** * This method resets the file pointer. */ publicfunctionrewind(): void { $this->rowCounter = 0; rewind($this->filePointer); }
/** * This method returns the current CSV row as a 2-dimensional array. * * @return array The current CSV row as a 2-dimensional array. */ publicfunctioncurrent(): array { $this->currentElement = fgetcsv($this->filePointer, self::ROW_SIZE, $this->delimiter); $this->rowCounter++;
return$this->currentElement; }
/** * This method returns the current row number. * * @return int The current row number. */ publicfunctionkey(): int { return$this->rowCounter; }
/** * This method checks if the end of file has been reached. * * @return bool Returns true on EOF reached, false otherwise. */ publicfunctionnext(): bool { if (is_resource($this->filePointer)) { return !feof($this->filePointer); }
returnfalse; }
/** * This method checks if the next row is a valid row. * * @return bool If the next row is a valid row. */ publicfunctionvalid(): bool { if (!$this->next()) { if (is_resource($this->filePointer)) { fclose($this->filePointer); }
from __future__ import annotations from collections.abc import Iterable, Iterator from typing importAny, List
""" 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): """ 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._collection)
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")
classAlphabeticalOrderIterator # In Ruby, the Enumerable mixin provides classes with several traversal and # searching methods, and with the ability to sort. The class must provide a # method each, which yields successive members of the collection. include Enumerable
# This attribute indicates the traversal direction. attr_accessor:reverse private :reverse
definitialize(collection = []) @collection = collection end
# The `iterator` method returns the iterator object itself, by default we # return the iterator in ascending order. defiterator AlphabeticalOrderIterator.new(@collection) end
# @return [AlphabeticalOrderIterator] defreverse_iterator AlphabeticalOrderIterator.new(@collection, true) end
# @param [String] item defadd_item(item) @collection << item end end
# 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.new collection.add_item('First') collection.add_item('Second') collection.add_item('Third')
/// Concrete Iterators implement various traversal algorithms. These classes /// store the current traversal position at all times. classWordsIterator: IteratorProtocol {
privatelet collection: WordsCollection privatevar index =0
funcmakeIterator() -> AnyIterator<Int> { var index =self.items.count -1
returnAnyIterator { defer { index -=1 } return index >=0?self.items[index] : nil } } }
/// Client does not know the internal representation of a given sequence. classClient { // ... staticfuncclientCode<S: Sequence>(sequence: S) { for item in sequence { print(item) } } // ... }
/// Let's see how it all works together. classIteratorConceptual: XCTestCase {
functestIteratorProtocol() {
let words =WordsCollection() words.append("First") words.append("Second") words.append("Third")
print("Straight traversal using IteratorProtocol:") Client.clientCode(sequence: words) }
functestAnyIterator() {
let numbers =NumbersCollection() numbers.append(1) numbers.append(2) numbers.append(3)
print("\nReverse traversal using AnyIterator:") Client.clientCode(sequence: numbers) } }
Output.txt: 执行结果
1 2 3 4 5 6 7 8 9
Straight traversal using IteratorProtocol: First Second Third
/** * Iterator Design Pattern * * Intent: Lets you traverse elements of a collection without exposing its * underlying representation (list, stack, tree, etc.). */
interfaceIterator<T> { // Return the current element. current(): T;
// Return the current element and move forward to next element. next(): T;
// Return the key of the current element. key(): number;
// Checks if current position is valid. valid(): boolean;
// Rewind the Iterator to the first element. rewind(): void; }
interfaceAggregator { // Retrieve an external iterator. getIterator(): Iterator<string>; }
/** * Concrete Iterators implement various traversal algorithms. These classes * store the current traversal position at all times. */
/** * 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. */ privateposition: number = 0;
/** * This variable indicates the traversal direction. */ privatereverse: boolean = false;
/** * Concrete Collections provide one or several methods for retrieving fresh * iterator instances, compatible with the collection class. */ classWordsCollectionimplementsAggregator { privateitems: string[] = [];
publicgetItems(): string[] { returnthis.items; }
publicgetCount(): number { returnthis.items.length; }
/** * 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. */ const collection = newWordsCollection(); collection.addItem('First'); collection.addItem('Second'); collection.addItem('Third');
const iterator = collection.getIterator();
console.log('Straight traversal:'); while (iterator.valid()) { console.log(iterator.next()); }