C++迭代器 iterator (二)


erator的概念源自於對遍歷一個線性容器工具的抽象,即如何你能訪問這個容器的某個元素。對於最簡單的數組,當然可以用數組的索引值,因為數組是連續存放在內存中的;但對於鏈表,就必須用指針。除此之外,還有還有很多種數據結構需要提供一個方便的工具來訪問其中的元素,方法有ID,關鍵字等等。為了統一所有的容器的這種工具的使用,一般提供一整套容器的開發者就會用一種方式來表示各種容器的訪問工具。例如C++ STL就是使用iterator。MFC自己的容器使用position。C#和java也有自己的方法,但方法是不變的。   
  iterator的用法可以被統一,但不同的底層容器實現其iterator的原理是不一樣的。例如iterator++你可以理解為移動到容器的下一個元素,如果底層如果是數組,把索引值加一就行;如果底層是鏈表,就得執行類似於m_pCurrent = m_pCurrent->pNext;的操作。因此每種容器都有自己的iterator實現方法。   
  C++ STL iterator的常用方法有:   
  iterator++ 移到下個元素   
  iterator-- 移到上個元素   
  *iterator 訪問iterator所指元素的值]   
  < > == != iterator之間的比較,例如判斷哪個元素在前   
  iterator1 + iterator2 iterator之間的加法運算,類似於指針加法

 

Iterator模式的幾種用法
在網絡上看帖子時發現不少模式的初學者對Iterator模式的理解僅僅停留在從類庫的容器類取得Iterator來遍歷容器中的內容的程度。
因此在這里寫幾個例子,來加深大家對Iterator模式的理解。
 
對容器中元素的訪問涉及到3個方面。
1.容器的類型
2.檢索容器內元素的方法
3.對元素的操作
比如說我們有一個表示書店的book_store類。里面保存了各種各樣的book類的實例。
book類有name和type兩種屬性。表示書的名字和類別。
因此book_store類內部會用一個容器來保存book的實例。比如list。
class book
{
public:
string name;
string type;
};
 
class book_store
{
private:
  list<book> m_books;
};
 
我們現在有這樣一個簡單的應用,那就是輸出所有的書名到屏幕。
那么我們來看一下在引入Iterator模式前有那幾種實現方法,各有什么缺點。
1.給book_store類增加一個print_book_name的函數。來實現這個功能。
這樣做的缺點有兩個:
(1).將輸入輸出邏輯和業務對象綁定在一起,導致了今后系統難以變更。
(2).輸出邏輯和內部實現綁定。
比如現在要把輸出到屏幕改成輸出到log文件的話,那么就需要修改print_book_name了。
2.給book_store類增加一個get_list函數。然后寫一個print_book類來負責打印書名的列表。這是一個初學者常用的方式。表面上看來似乎兩個類各擔其責,一個表示業務對象一個負責打印。
如果需要打印到log文件的話,只要新增加一個log_book類,book_store和print_book都不受影響。解決了上面的這個問題。
這樣做的缺點是:
(1).把book_store類的內部實現給暴露出來了,違反了封裝的原則。
如果現在把內部容器類型從list換成了vector的話,就要修改輸出邏輯了。也就是說,要同時改寫print_book類和log_book類。
3.增加一個list和vector類共同的基類/接口,比如I_container。然后給book_store類增加一個get_books函數,返回I_container。
這在一定程度上解決了上面的問題。但是並不徹底。應為還是暴露了內部的實現,只不過從list上升到了I_container。
· 如果現在系統發生了變化,book_store不再在本地保存books了,而是需要通過網絡取得的話,print_book和log_book就無法對應了。
· 另一個限制是,我需要一個新的機能,那就是打印所有type為”烹飪書”的機能的話,就需要一個print_cook_book類了,而這里邊的格式化代碼和輸出代碼和print_book是相同的。重復代碼是維護的噩夢。
 
接下來我們看一下Iterator模式如何解決以上的這些問題。
首先,我們引入一個I_iterator的Interface。
然后創建一個I_iterator的實現類all_book_iterator。這個類可以迭代book_store中的所有book。
接下來創建一個print_book類,從I_iterator中取得每一個book,然后打印到屏幕。
 
下面我們看一下如何對應上面的這些需求變更。
1.要求輸出到log文件
追加一個log_book類,其他都類都不需要改變。
2.將內部容器從list變成vector。
修改iterator中的相關代碼。Iterator的使用者不會受到影響。
3.從網絡取得數據。
修改iterator中的相關代碼。Iterator的使用者不會受到影響。
4.按照type檢索
在iterator中添加一個type的屬性,或者是構造一個新的type_search_iterator。
在iterator中把不符合檢索條件的book過濾掉。
5.按照某一特定順序輸出book名到屏幕,或是log文件。
實現一個按該順序輸出的iterator。
6.以同樣的方式打印cd_store。
實現對應於cd_store的iterator。
 
可見,iterator模式在各種iterator中封裝了檢索元素的方法。
將容器和對容器中元素的操作完全隔開。
大大增加了代碼的可重用性




FROM:  http://fengqing888.blog.163.com/blog/static/330114162010510068620/


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com