gpt4 book ai didi

c++ - C++ 中基于接口(interface)的编程结合迭代器。如何保持这种简单?

转载 作者:可可西里 更新时间:2023-11-01 16:39:03 24 4
gpt4 key购买 nike

在我的开发中,我正在慢慢地从面向对象的方法转向基于接口(interface)的编程方法。更准确地说:

  • 过去,如果我能将逻辑分组到一个类中,我就已经很满足了
  • 现在我倾向于将更多逻辑放在接口(interface)后面,让工厂创建实现

一个简单的例子说明了这一点。

过去我写过这些类:

  • 图书馆

现在我写这些类:

  • 图书馆
  • 图书馆
  • 图书馆工厂
  • 电子书
  • 书厂

这种方法使我能够轻松地为我的每个接口(interface)实现模拟类,并在较慢的旧实现和较快的新实现之间切换,并在同一应用程序中对它们进行比较。

在大多数情况下,这工作得很好,但如果我想使用迭代器循环集合,它就会成为一个问题。

假设我的图书馆有一系列书籍,我想遍历它们。在过去这不是问题:Library::begin() 和 Library::end() 返回一个迭代器 (Library::iterator),我可以在其上轻松编写一个循环,如下所示:

for (Library::iterator it=myLibrary.begin();it!=mylibrary.end();++it) ...

问题是在基于接口(interface)的方法中,不能保证 ILibrary 的不同实现使用同一种迭代器。如果例如OldLibrary 和 NewLibrary 都继承自 ILibrary,则:

  • OldLibrary 可以使用 std::vector 来存储其书籍,并在其开始和结束方法中返回 std::vector::const_iterator
  • NewLibrary 可以使用 std::list 来存储其书籍,并在其开始和结束方法中返回 std::list::const_iterator

要求两个 ILibrary 实现返回相同类型的迭代器也不是解决方案,因为在实践中,增量操作 (++it) 需要在两个实现中以不同方式实现。

这意味着在实践中我也必须使迭代器成为一个接口(interface),这意味着应用程序不能将迭代器放在堆栈上(典型的 C++ 切片问题)。

我可以通过将迭代器接口(interface)包装在一个非接口(interface)类中来解决这个问题,但对于我试图解决的问题来说,这似乎是一个相当复杂的解决方案。

有没有更好的方法来处理这个问题?

编辑:Martin 发言后的一些澄清。

假设我有一个类可以返回所有按受欢迎程度排序的书籍:LibraryBookFinder。它有 begin() 和 end() 方法,它们返回一个 LibraryBookFinder::const_iterator,它指的是一本书。

为了用全新的实现替换我的旧实现,我想将旧的 LibraryBookFinder 放在接口(interface) ILibraryBookFinder 后面,并将旧的实现重命名为 OldSlowLibraryBookFinder。

然后,我的名为 VeryFastCachingLibraryBookFinder 的新(极快)实现可以继承自 ILibraryBookFinder。这就是迭代器问题的来源。

下一步可能是将接口(interface)隐藏在工厂后面,在那里我可以要求工厂“给我一个非常擅长根据受欢迎程度、标题或作者返回书籍的‘查找器’,......你最终得到这样的代码:

ILibraryBookFinder *myFinder = LibraryBookFinderFactory (FINDER_POPULARITY);
for (ILibraryBookFinder::const_iterator it=myFinder->begin();it!=myFinder.end();++it) ...

或者如果我想使用其他标准:

ILibraryBookFinder *myFinder = LibraryBookFinderFactory (FINDER_AUTHOR);
for (ILibraryBookFinder::const_iterator it=myFinder->begin();it!=myFinder.end();++it) ...

LibraryBookFinderFactory 的参数可能由外部因素决定:配置设置、命令行选项、对话框中的选择……并且每个实现都有其自己的优化类型(例如,一本书的作者不' 变化,所以这可以是一个非常静态的缓存;受欢迎程度每天都在变化,这可能意味着完全不同的数据结构)。

最佳答案

你在这里混合了隐喻。

如果库是容器,那么它需要自己的迭代器,它不能重复使用成员的迭代器。因此,您可以将成员迭代器包装在 ILibraryIterator 的实现中。

但严格来说,库不是容器,它是库。
因此,库上的方法是您可以在库上执行的操作(这里想想动词)。库可能包含容器,但严格来说它不是容器,因此不应公开 begin() 和 end()。

因此,如果您想对书籍执行操作,您应该要求图书馆执行该操作(通过提供仿函数)。类的概念是它是自包含的。用户不应该使用 getter 来获取有关对象的内容,然后将内容放回对象应该知道如何对自身执行操作(这就是为什么我讨厌 getters/setters,因为它们破坏了封装)。

class ILibrary
{
public:
IBook const& getBook(Index i) const;

template<R,A>
R checkBooks(A const& librarianAction);
};

关于c++ - C++ 中基于接口(interface)的编程结合迭代器。如何保持这种简单?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3968439/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com