本文记录我对迭代器的一点理解。先列出参考的文章[LevelDB源码分析–使用Iterator简化代码设计]。我对参考文章的内容自己做了实现,我讲的不清楚的地方可以直接参考原文。
用迭代器可以很大程度上隔离容器底层实现,使用时只需依赖迭代器相对统一的方法/接口。
这是为什么要设计迭代器这个东西,我在看ACC的时候,容器-迭代器-算法这三者有着密不可分的关系,算法通过迭代器作用于容器,迭代器相当于起到了媒介的作用,这是它的功能。但是,上面说的才是为什么要设计这样的一个东西。
说说上面的代码,我的目的是为了遍历shelf里面的book,那么问题来了。
为什么不把遍历方法写在Shelf里面? 作为类的设计者,无法了解过多的应用场景,只能是提供最基本的接口。比如对于Shelf的遍历可能有很多种,输出所有元素,输出所有元素+逗号,输出所有元素+\ ……所有,遍历的场景可能有很多,这个不应该由类的设计者来提供。所以,不能写在类的里面。
既然不使用迭代器可以遍历,那么为什么还要使用迭代器遍历 先说一个从文章开始处的链接中学到的东西,对于非迭代器遍历的方法,traverse需要知道shelf_的类型,那么如果现在不用vector< Book >去实现,而是换成了list< Book >,那么类的使用者需要该这里的参数类型,相当于向类的使用者暴露了过多的内部信息。其实,我觉得这个还倒是其次,这么做没有屏蔽实现的细节,通常情况下,类的使用者是不需要关注类的实现细节的,所以这么做不好。
为什么迭代器遍历的方式好? 有了上文的分析,就很容易看出,及时Shelf的设计换成了list< Book >,遍历的接口也任然不需要修改,因为迭代器类型屏蔽了底层实现的机制,用户只需专注怎么更好的使用即可。
用迭代器可以很大程度上隔离容器底层实现,使用时只需依赖迭代器相对统一的方法/接口。
看了leveldb迭代器设计之后,再看原文链接的感触。
不采用迭代器的设计,客户端暴露了内部的实现。
#include <iostream> #include <string> #include <vector> namespace TJU{ class Shelf { public: Shelf() {} void push_back(const std::string& book) { books_.push_back(book); } std::vector<std::string> get_books() const { return books_; } private: std::vector<std::string> books_; };// shelf class BookStore { public: BookStore() {} void push_back( const Shelf& shelf ) { shelfs_.push_back(shelf); } std::vector<Shelf> get_shelfs() const { return shelfs_; } private: std::vector<Shelf> shelfs_; };// BookStore }// namespace TJU int main(){ TJU::BookStore store; TJU::Shelf math; math.push_back( "linear algebra" ); math.push_back( "calculus" ); math.push_back( "statics" ); TJU::Shelf cs; cs.push_back("java"); cs.push_back( "c++" ); cs.push_back( "AI" ); store.push_back(math); store.push_back(cs); /* iterate the books */ std::vector<TJU::Shelf> shelfs = store.get_shelfs(); int sz = shelfs.size(); for( int i = 0; i < sz; ++i ){ std::vector<std::string> books = shelfs[i].get_books(); int sz1 = books.size(); for( int j = 0; j < sz1; ++j ){ std::cout << books[j] << " "; } std::cout << std::endl; } return 0; }模仿我之前对于vector的实现,内部提供迭代器类型,供外部访问。现在遍历屏蔽了底层的实现。
#include <iostream> #include <string> #include <vector> namespace TJU{ class Shelf { public: Shelf() {} void push_back(const std::string& book) { books_.push_back(book); } public: typedef std::vector<std::string>::iterator Iterator; Iterator begin() { return books_.begin(); } Iterator end() { return books_.end(); } private: std::vector<std::string> books_; };// shelf class BookStore { public: BookStore() {} void push_back( const Shelf& shelf ) { shelfs_.push_back(shelf); } public: typedef std::vector<Shelf>::iterator Iterator; Iterator begin() { return shelfs_.begin(); } Iterator end() { return shelfs_.end(); } private: std::vector<Shelf> shelfs_; };// BookStore }// namespace TJU int main(){ TJU::BookStore store; TJU::Shelf math; math.push_back( "linear algebra" ); math.push_back( "calculus" ); math.push_back( "statics" ); TJU::Shelf cs; cs.push_back("java"); cs.push_back( "c++" ); cs.push_back( "AI" ); store.push_back(math); store.push_back(cs); /* iterate the books */ TJU::BookStore::Iterator b = store.begin(); TJU::BookStore::Iterator e = store.end(); while( b != e ){ TJU::Shelf::Iterator bb = b->begin(); TJU::Shelf::Iterator ee = b->end(); while( bb != ee ){ std::cout << *bb << " "; ++bb; } std::cout << std::endl; ++b; } return 0; }