一次性课程

时间:2011-07-07 02:36:53

标签: c++ class design-patterns

在我正在进行的项目中,我们有几个“一次性”课程。我所说的一次性是他们是一个类,你可以调用一些方法来设置信息,你调用什么等同于doit函数。你doit一次扔掉它们。如果您想再次doit,则必须创建该类的另一个实例。它们没有被简化为单个函数的原因是它们必须在它们doit之后存储状态,以便用户获取有关所发生事件的信息,并且通过引用参数返回一堆内容似乎不是很干净。它不是单身人士,也不是普通人。

这是一种糟糕的做事方式吗?这类东西有更好的设计模式吗?或者我应该放弃并让用户传递一大堆参考参数来返回一堆东西?

6 个答案:

答案 0 :(得分:4)

您所描述的是 不是类 (状态+改变它的方法), 但是算法 (将输入数据映射到输出数据):

result_t do_it(parameters_t);

为什么你认为你需要上课?

答案 1 :(得分:3)

听起来你的类基本上是一个伪装的参数块。

这个IMO没有任何问题,它肯定比有这么多参数的功能更好,很难跟踪哪个是哪个。

当有很多输入参数时,这也是一个好主意 - 一些设置方法可以一次设置其中一些,因此设置功能的名称可以提供更多关于哪个参数的线索。此外,您可以使用其他设置器功能 - 过载或使用不同的名称来涵盖设置相同参数的不同方法。您甚至可以使用简单的状态机或标记系统来确保完成正确的设置。

但是,实际上可以回收实例而无需删除和重新创建。也许是一种“重置”方法。

  • 正如康拉德所说,这可能会产生误导。复位方法不应该被视为构造函数的替代 - 构造函数将对象置于自洽的初始化状态,而不是重置方法。对象应始终保持自洽。
  • 除非有理由进行累积运行 - 总样式的do-it调用,否则调用者不应该明确地调用reset - 它应该作为第一步内置到do-it调用中。
  • 我仍然决定,反思,打击 - 不是因为Jalfs评论,而是因为我不得不分裂以争论点;-) - 基本上,我图我几乎总是有这种类型的重置方法,部分原因是我的“工具”通常有多种相关的“做它”(例如“插入”,“搜索”和“删除”树形工具),以及共享模式。该模式只是一些输入字段,在参数块术语中,但这并不意味着我想继续重新初始化。 但仅仅因为这种模式对我来说很重要,并不意味着它应该是一个原则点。

我甚至为这些事情命名(不限于单一操作案例) - “工具”类。例如,“tree_searching_tool”将是一个搜索(但不包含)树的类,但实际上我有一个“tree_tool”,它实现了几个与树相关的操作。

基本上,即使是C中的参数块,理想情况下也应该提供一种抽象,除了只是一堆参数之外,它还能提供一些顺序。 “工具”是一种(模糊的)抽象。类是在C ++中处理抽象的主要方法。

答案 2 :(得分:2)

我使用过similar design并对此感到疑惑。虚构的简化示例可能如下所示:

FileDownloader downloader(url);
downloader.download();
downloader.result(); // get the path to the downloaded file

为了使其可重复使用,我将其存储在boost::scoped_ptr

boost::scoped_ptr<FileDownloader> downloader;

// Download first file
downloader.reset(new FileDownloader(url1));
downloader->download();

// Download second file
downloader.reset(new FileDownloader(url2));
downloader->download();

回答你的问题:我认为没问题。我没有发现这个设计有任何问题。

答案 3 :(得分:1)

据我所知,你正在描述一个代表算法的类。您配置算法,然后运行算法,然后您获得算法的结果。如果替代方案是一个需要7个配置参数和5个输出引用的函数,我认为将这些步骤放在一个类中没有错。

这种代码结构的优点还在于您可以将算法分成几个步骤并将它们放在单独的私有成员函数中。您也可以在没有类的情况下执行此操作,但如果算法具有大量状态,则可能导致子函数具有许多参数。在类中,您可以通过成员变量方便地表示该状态。

您可能需要注意的一件事是,像这样构建代码很容易诱使您使用继承来在类似的算法之间共享代码。如果算法A定义了算法B需要的私有辅助函数,则很容易使该成员函数受到保护,然后通过让类B从类A派生来访问该辅助函数。定义包含该类的第三类C也是很自然的。公共代码,然后有A和B派生自C.根据经验,仅用于在非虚方法中共享代码的继承不是最好的方法 - 它不灵活,你最终不得不承担数据的成员超类,你打破了超类的封装。根据这种情况的经验法则,更喜欢在不使用继承的情况下将公共代码从两个类中分解出来。您可以将该代码分解为非成员函数,或者您可以将其分解为一个实用程序类,然后使用该实用程序类而不从中派生它。

YMMV - 什么是最好的取决于具体情况。将代码分解为公共超类是template method pattern的基础,因此在使用虚方法时,继承可能就是您想要的。

答案 4 :(得分:0)

这个概念没什么特别的错。您应该尝试对其进行设置,以便通常可以自动分配相关对象而不必更新 - 在大多数情况下可以显着节省性能。除非您知道编译器有效地生成它,否则您可能不应该将该技术用于对性能敏感的代码。

答案 5 :(得分:0)

我不同意你所描述的课程“不是正常的课程”。它有状态,有行为。你已经指出它的寿命相对较短,但这并不会使它成为一个阶级。

短期课程与具有外部参数的功能: 我同意你的短期课程可能比一个需要许多out-params(或1个复杂的out-param)的函数更直观,更容易维护。但是,我怀疑一个函数会稍微好一点,因为你不会花时间来实例化一个新的短期对象。如果它是一个简单的类,那么性能差异可能是微不足道的。但是,如果您谈论的是性能极其严重的环境,那么可能需要考虑一下。

短期课程:创建新实例与重复使用实例: 有很多例子可以重复使用类的实例:线程池,数据库连接池(可能靠近'pool'结尾的任何软件结构:)。根据我的经验,它们似乎在实例化对象是一项昂贵的操作时使用。你的小型,短命的课程听起来并不像实例化它们那么昂贵,所以我不打算尝试重复使用它们。您可能会发现,无论您需要什么池化机制,实际上都比仅仅在需要时实例化新对象花费更多(性能方面)。