Pat*_*ick 9 c++ iterator design-patterns interface
在我的开发中,我正在慢慢地从面向对象的方法转向基于接口的编程方法.更确切地说:
一个简单的例子澄清了这一点.
过去我写过这些课程:
现在我写这些类:
这种方法允许我轻松地为每个接口实现模拟类,并在旧的,较慢的实现和新的,更快的实现之间切换,并在同一个应用程序中进行比较.
对于大多数情况,这非常好,但如果我想使用迭代器来循环集合,它就会成为一个问题.
假设我的图书馆有一系列书籍,我想对它们进行迭代.在过去,这不是问题:Library :: begin()和Library :: end()返回一个迭代器(Library :: iterator),我可以在其上轻松编写循环,如下所示:
for (Library::iterator it=myLibrary.begin();it!=mylibrary.end();++it) ...
Run Code Online (Sandbox Code Playgroud)
问题是在基于接口的方法中,不能保证ILibrary的不同实现使用相同类型的迭代器.如果例如OldLibrary和NewLibrary都继承自ILibrary,那么:
要求两个ILibrary实现都返回相同类型的迭代器也不是解决方案,因为在实践中,增量操作(++ it)需要在两个实现中以不同方式实现.
这意味着在实践中我必须使迭代器成为一个接口,这意味着应用程序不能将迭代器放在堆栈上(典型的C++切片问题).
我可以通过在非接口类中包装iterator接口来解决这个问题,但对于我尝试obtian的东西,这似乎是一个非常复杂的解决方案.
有没有更好的方法来处理这个问题?
编辑: 马丁发表评论后的一些澄清.
假设我有一个类,它返回按受欢迎程度排序的所有书籍:LibraryBookFinder.它有begin()和end()方法,它们返回一个引用书籍的LibraryBookFinder :: const_iterator.
要用一个全新的实现替换旧的实现,我想将旧的LibraryBookFinder放在ILibraryBookFinder接口后面,并将旧实现重命名为OldSlowLibraryBookFinder.
然后我的名为VeryFastCachingLibraryBookFinder的新(快速快速)实现可以继承ILibraryBookFinder.这是迭代器问题的来源.
下一步可能是隐藏工厂后面的界面,在那里我可以要求工厂"给我一个'发现者'非常擅长根据人气,或根据标题,或作者,...返回书籍.你最终得到了像这样的代码:
ILibraryBookFinder *myFinder = LibraryBookFinderFactory (FINDER_POPULARITY);
for (ILibraryBookFinder::const_iterator it=myFinder->begin();it!=myFinder.end();++it) ...
Run Code Online (Sandbox Code Playgroud)
或者如果我想使用其他标准:
ILibraryBookFinder *myFinder = LibraryBookFinderFactory (FINDER_AUTHOR);
for (ILibraryBookFinder::const_iterator it=myFinder->begin();it!=myFinder.end();++it) ...
Run Code Online (Sandbox Code Playgroud)
LibraryBookFinderFactory的参数可以由外部因素决定:配置设置,命令行选项,对话框中的选择,......每个实现都有自己的优化(例如,书籍的作者不会改变)所以这可以是一个非常静态的缓存;流行度可以每天改变,这可能意味着完全不同的数据结构).
你在这里混合了隐喻。
如果库是一个容器,那么它需要自己的迭代器,它不能重用成员的迭代器。因此,您可以将成员迭代器包装在 ILibraryIterator 的实现中。
但严格来说,图书馆不是一个容器,而是一个图书馆。
因此,库上的方法是您可以在库上执行的操作(此处考虑动词)。库可能包含容器,但严格来说它不是容器,因此不应公开 begin() 和 end()。
因此,如果您想对书籍执行操作,您应该要求图书馆执行该操作(通过提供函子)。类的概念是它是自包含的。用户不应该使用 getter 来获取有关对象的内容,然后将内容放回对象应该知道如何对其自身执行操作(这就是为什么我讨厌 getter/setter,因为它们破坏了封装)。
class ILibrary
{
public:
IBook const& getBook(Index i) const;
template<R,A>
R checkBooks(A const& librarianAction);
};
Run Code Online (Sandbox Code Playgroud)