<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>iterator</title>
	<atom:link href="https://www.aitaocui.cn/tag/185567/feed" rel="self" type="application/rss+xml" />
	<link>https://www.aitaocui.cn</link>
	<description>翡翠玉石爱好者聚集地</description>
	<lastBuildDate>Wed, 23 Nov 2022 11:46:48 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.1.1</generator>

<image>
	<url>https://www.aitaocui.cn/wp-content/uploads/2022/11/taocui.png</url>
	<title>iterator</title>
	<link>https://www.aitaocui.cn</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>iterator(软件设计模式)</title>
		<link>https://www.aitaocui.cn/article/290777.html</link>
					<comments>https://www.aitaocui.cn/article/290777.html#respond</comments>
		
		<dc:creator><![CDATA[郭梓文]]></dc:creator>
		<pubDate>Wed, 23 Nov 2022 11:46:48 +0000</pubDate>
				<category><![CDATA[百科]]></category>
		<category><![CDATA[iterator]]></category>
		<guid isPermaLink="false">https://www.aitaocui.cn/?p=290777</guid>

					<description><![CDATA[迭代器（Iterator）模式，又叫做游标（Cursor）模式。GOF给出的定义为：提供一种方法访问一个容器（container）对象中各个元素，而又不需暴露该对象的内部细节。从定...]]></description>
										<content:encoded><![CDATA[</p>
<article>
<p>迭代器（Iterator）模式，又叫做游标（Cursor）模式。GOF给出的定义为：提供一种方法访问一个容器（container）对象中各个元素，而又不需暴露该对象的内部细节。从定义可见，迭代器模式是为容器而生。很明显，对容器对象的访问必然涉及到遍历算法。你可以一股脑的将遍历方法塞到容器对象中去；或者根本不去提供什么遍历算法，让使用容器的人自己去实现去吧。这两种情况好像都能够解决问题。</p>
</article>
<article>
<h1>定义结构</h1>
<p>然而在前一种情况，容器承受了过多的功能，它不仅要负责自己“容器”内的元素维护（添加、删除等等），而且还要提供遍历自身的接口；而且由于遍历状态保存的问题，不能对同一个容器对象同时进行多个遍历。第二种方式倒是省事，却又将容器的内部细节暴露无遗。</p>
<p>而迭代器模式的出现，很好的解决了上面两种情况的弊端。先来看下迭代器模式的真面目吧。</p>
<p>迭代器模式由以下角色组成：</p>
<p>1).迭代器角色（Iterator）：迭代器角色负责定义访问和遍历元素的接口。</p>
<p>2).具体迭代器角色（Concrete Iterator）：具体迭代器角色要实现迭代器接口，并要记录遍历中的当前位置。</p>
<p>3).容器角色（Container）：容器角色负责提供创建具体迭代器角色的接口。</p>
<p>4).具体容器角色（Concrete Container）：具体容器角色实现创建具体迭代器角色的接口——这个具体迭代器角色与该容器的结构相关。</p>
<p>迭代器模式的类图如下：</p>
<p>从结构上可以看出，迭代器模式在客户与容器之间加入了迭代器角色。迭代器角色的加入，就可以很好的避免容器内部细节的暴露，而且也使得设计符合“单一职责原则”。</p>
<p>注意，在迭代器模式中，具体迭代器角色和具体容器角色是耦合在一起的——遍历算法是与容器的内部细节紧密相关的。为了使客户程序从与具体迭代器角色耦合的困境中脱离出来，避免具体迭代器角色的更换给客户程序带来的修改，迭代器模式抽象了具体迭代器角色，使得客户程序更具一般性和重用性。这被称为多态迭代。</p>
<h1>适用情况</h1>
<p>由上面的讲述，我们可以看出迭代器模式给容器的应用带来以下好处：</p>
<p>1).支持以不同的方式遍历一个容器角色。根据实现方式的不同，效果上会有差别。</p>
<p>2).简化了容器的接口。但是在java Collection中为了提高可扩展性，容器还是提供了遍历的接口。</p>
<p>3).对同一个容器对象，可以同时进行多个遍历。因为遍历状态是保存在每一个迭代器对象中的。</p>
<p>由此也能得出迭代器模式的适用范围：</p>
<p>1).访问一个容器对象的内容而无需暴露它的内部表示。</p>
<p>2).支持对容器对象的多种遍历。</p>
<p>3).为遍历不同的容器结构提供一个统一的接口（多态迭代）。</p>
<h1>简介</h1>
<p>Iterator（迭代器）模式又称Cursor（游标）模式，用于提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。或者这样说可能更容易理解：Iterator模式是运用于聚合对象的一种模式，通过运用该模式，使得我们可以在不知道对象内部表示的情况下，按照一定顺序（由iterator提供的方法）访问聚合对象中的各个元素。</p>
<p>由于Iterator模式的以上特性：与聚合对象耦合，在一定程度上限制了它的广泛运用，一般仅用于底层聚合支持类，如STL的list、vector、stack等容器类及ostream_iterator等扩展iterator。</p>
<p>根据STL中的分类，iterator包括：</p>
<p>输入迭代器（Input Iterator）：通过对输入迭代器解除引用，它将引用对象，而对象可能位于集合中。最严格的输入迭代只能以只读方式访问对象。</p>
<p>输出迭代器（Output Iterator）：该类迭代器和Input Iterator极其相似，也只能单步向前迭代元素，不同的是该类迭代器对元素只有写的权力。</p>
<p>以上两种基本迭代器可进一步分为三类：</p>
<p>前向迭代器（Forward Iterator）：该类迭代器可以在一个正确的区间中进行读写操作，它拥有Input Iterator的所有特性，和Output Iterator的部分特性，以及单步向前迭代元素的能力。</p>
<p>双向迭代器（Bidirectional Iterator）：该类迭代器是在Forward Iterator的基础上提供了单步向后迭代元素的能力。</p>
<p>随机迭代器（Random Access Iterator）：该类迭代器能完成上面所有迭代器的工作，它自己独有的特性就是可以像指针那样进行算术计算，而不是仅仅只有单步向前或向后迭代。</p>
<p>vector和deque提供的是RandomAccessIterator，list提供的是BidirectionalIterator，set和map提供的iterators是ForwardIterator，关于STL中iterator的更多信息，请阅读参考1或2。</p>
<h2 id="a-9900d092">应用</h2>
<p>Iterator模式有三个重要的作用：</p>
<p>1）它支持以不同的方式遍历一个聚合，复杂的聚合可用多种方式进行遍历，如二叉树的遍历，可以采用前序、中序或后序遍历。迭代器模式使得改变遍历算法变得很容易:仅需用一个不同的迭代器的实例代替原先的实例即可，你也可以自己定义迭代器的子类以支持新的遍历，或者可以在遍历中增加一些逻辑，如有条件的遍历等。</p>
<p>2）迭代器简化了聚合的接口，有了迭代器的遍历接口，聚合本身就不再需要类似的遍历接口了，这样就简化了聚合的接口。</p>
<p>3）在同一个聚合上可以有多个遍历，每个迭代器保持它自己的遍历状态，因此你可以同时进行多个遍历。</p>
<p>4）此外，Iterator模式可以为遍历不同的聚合结构（需拥有相同的基类）提供一个统一的接口，即支持多态迭代。</p>
<p>简单说来，迭代器模式也是Delegate原则的一个应用，它将对集合进行遍历的功能封装成独立的Iterator，不但简化了集合的接口，也使得修改、增加遍历方式变得简单。从这一点讲，该模式与Bridge模式、Strategy模式有一定的相似性，但Iterator模式所讨论的问题与集合密切相关，造成在Iterator在实现上具有一定的特殊性，具体将在示例部分进行讨论。</p>
<p>正如前面所说，与集合密切相关，限制了Iterator模式的广泛使用。在一般的底层集合支持类中，我们往往不愿“避轻就重”将集合设计成集合+Iterator的形式，而是将遍历的功能直接交由集合完成，以免犯了“过度设计”的诟病，但是，如果我们的集合类确实需要支持多种遍历方式（仅此一点仍不一定需要考虑Iterator模式，直接交由集合完成往往更方便），或者，为了与系统提供或使用的其它机制，如STL算法，保持一致时，Iterator模式才值得考虑。</p>
<h2 id="a-577018b5">举例</h2>
<p>可以考虑使用两种方式来实现Iterator模式：内嵌类或者友元类。通常迭代类需访问集合类中的内部数据结构，为此，可在集合类中设置迭代类为friend class，但这不利于添加新的迭代类，因为需要修改集合类，添加friend class语句。也可以在抽象迭代类中定义protected型的存取集合类内部数据的函数，这样迭代子类就可以访问集合类数据了，这种方式比较容易添加新的迭代方式，但这种方式也存在明显的缺点：这些函数只能用于特定聚合类，并且，不可避免造成代码更加复杂。</p>
<p>STL的list::iterator、deque::iterator、rbtree::iterator等采用的都是外部Iterator类的形式，虽然STL的集合类的iterator分散在各个集合类中，但由于各Iterator类具有相同的基类，保持了相同的对外的接口（包括一些traits及tags等，感兴趣者请认真阅读参考1、2），从而使得它们看起来仍然像一个整体，同时也使得应用algorithm成为可能。我们如果要扩展STL的iterator，也需要注意这一点，否则，我们扩展的iterator将可能无法应用于各algorithm。</p>
<p>以下是一个遍历二叉树的Iterator的例子，为了方便支持多种遍历方式，并便于遍历方式的扩展，其中还使用了Strategy模式（见笔记21）：</p>
<p>（注：1、虽然下面这个示例是本系列所有示例中花费我时间最多的一个，但我不得不承认，它非常不完善，感兴趣的朋友，可以考虑参考下面的参考材料将其补充完善，或提出宝贵改进意见。2、我本想考虑将其封装成与STL风格一致的形式，使得我们遍历二叉树必须通过Iterator来进行，但由于二叉树在结构上较线性存储结构复杂，使访问必须通过Iterator来进行，但这不可避免使得BinaryTree的访问变得异常麻烦，在具体应用中还需要认真考虑。3、以下只提供了Inorder&lt;中序&gt;遍历iterator的实现。）</p>
<p>#include </p>
<p>#include </p>
<p>#include </p>
<p>#include </p>
<p>#include </p>
<p>using namespace std;</p>
<p>template </p>
<p>class BinaryTree;</p>
<p>template </p>
<p>class Iterator;</p>
<p>template </p>
<p>class BinaryTreeNode</p>
<p>{</p>
<p>public:</p>
<p>typedef BinaryTreeNode NODE;</p>
<p>typedef BinaryTreeNode* NODE_PTR;</p>
<p>BinaryTreeNode(const T&amp; element) : data(element), leftChild(NULL), rightChild(NULL), parent(NULL) { }</p>
<p>BinaryTreeNode(const T&amp; element, NODE_PTR leftChild, NODE_PTR rightChild)</p>
<p>:data(element), leftChild(leftChild), rightChild(rightChild), parent(NULL)</p>
<p>{</p>
<p>if (leftChild)</p>
<p>leftChild-&gt;setParent(this);</p>
<p>if (rightChild)</p>
<p>rightChild-&gt;setParent(this);</p>
<p>}</p>
<p>T getData(void) const { return data; }</p>
<p>NODE_PTR getLeft(void) const { return leftChild; }</p>
<p>NODE_PTR getRight(void) const { return rightChild; }</p>
<p>NODE_PTR getParent(void) const { return parent; }</p>
<p>void SetData(const T&amp; data) { this-&gt;data = item; }</p>
<p>void setLeft(NODE_PTR ptr) { leftChild = ptr; ptr-&gt;setParent(this); }</p>
<p>void setRight(NODE_PTR ptr) { rightChild = ptr; ptr-&gt;setParent(this); }</p>
<p>void setParent(NODE_PTR ptr) { parent = ptr; }</p>
<p>private:</p>
<p>T data;</p>
<p>NODE_PTR leftChild;</p>
<p>NODE_PTR rightChild;</p>
<p>NODE_PTR parent; // pointer to parent node, needed by iterator</p>
<p>friend class BinaryTree;</p>
<p>};</p>
</article>
<div class="mt-3 mb-3" style="max-width: 770px;height: auto;">
                                    </div>
<div class="mt-3 mb-3" style="max-width: 770px;height: auto;">
                                    </div>
<div class="mt-3 mb-3" style="max-width: 770px;height: auto;">
                                    </div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.aitaocui.cn/article/290777.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
