【问题标题】:C++ program design questionC++程序设计题
【发布时间】:2010-06-28 17:40:42
【问题描述】:

在我最近参与的几个项目中,我几乎沉迷于以下编码模式:(我不确定是否有合适的名称,但无论如何......)

假设某个对象处于某个确定的状态,我们不想从外部更改此状态。这些更改可能意味着任何行为,可能调用任何算法,但事实是它们专注于更改某些对象的状态(成员状态、数据状态等...)。

我们将更改这些对象的一种离散方式称为Mutator。 Mutators 被应用一次(通常),它们有一些内部方法,如 apply(Target& target, ...),它会立即引发更改对象的状态 (实际上,它们是某种函数式对象)。

它们也可以很容易地融入链并一个接一个地应用(Mutator m1, m2, ...);它们也可以通过virtual void apply(...) 方法从一些基本的BasicMutator 派生而来。

我已经介绍了名为InnerMutator 和ExplicitMutator 的类,它们在访问方面有所不同——它们中的第一个也可以更改对象的内部状态,并且应该声明为朋友(@ 987654329@).


在这些项目中,我的逻辑变成了以下方式:

  1. 准备可用的修改器,选择要应用的修改器
  2. 创建 object 并将其设置为某个确定的状态
  3. foreach (mutator) mutator.apply(object);

现在是问题。

这个方案运行良好,并且 (对我来说) 似乎是一些非标准但有用的设计的样本 图案。

让我感到不舒服的是 InnerMutator 的东西。我不 认为将 mutator 声明为朋友 每个对象的状态可能是 改变是个好主意,我不想 找到合适的替代品。

这种情况可以用Mutators 解决吗? 建议一些替代模式 结果一样吗?

谢谢。

【问题讨论】:

  • 如果你能给我们一些具体的例子,这可能有助于确定你的方法是否值得稍微奇怪的做事方式。

标签: c++ mutators


【解决方案1】:

我希望这不是冒犯性的,但我不禁认为这种设计对于一个相当简单的问题来说是一个过于花哨的解决方案。

例如,为什么需要聚合 mutators?只能写:

template <class T>
void mutate(T& t)
{
    t.mutate1(...);
    t.mutate2(...);
    t.mutate3(...);
}

这里有你的聚合修改器,只是它是一个简单的函数模板,依赖于静态多态性,而不是一个组合的修改器列表构成一个超级修改器。

我曾经做过一些可能相当相似的事情。我制作了可以通过运算符 && 组合成应用两个操作数(按从左到右的顺序)的超级函数对象的函数对象,这样就可以编写如下代码:

foreach(v.begin(), v.end(), attack && burn && drain);

当时它真的很简洁,对我来说似乎很聪明,而且它非常高效,因为它动态生成了新的函数对象(不涉及运行时机制),但是当我的同事看到它时,他们认为我是疯狂的。回想起来,我试图把所有东西都塞进函数式编程中,它有它的用处,但在 C++ 中可能不应该过度依赖。写起来很容易:

BOOST_FOR_EACH(Something& something, v)
{
    attack(something);
    burn(something);
    drain(something);
}

当然,它的代码行数更多,但它具有集中化和易于调试的优点,并且不会向使用我的代码的其他人引入陌生的概念。我发现专注于严格的逻辑而不是试图强行减少代码行数更有益。

我建议您对此进行深入思考,并认真考虑是否值得继续使用这种基于 mutator 的设计,无论它多么聪明和紧凑。如果其他人不能很快理解,除非你有 boost 作者的权威,否则很难说服人们喜欢它。

至于 InnerMutator,我认为你应该像避免瘟疫一样避免它。拥有可以在此处尽可能直接地修改类的内部的外部 mutator 类完全违背了拥有内部的许多目的。

【讨论】:

    【解决方案2】:

    将那些Mutators 方法简单地添加到它们正在更改的类中不是更好吗?如果您希望多个类具有共同的功能,那么为什么不让它们从同一个基类继承呢?这样做可以解决我想象的所有内部突变体不适。

    如果您想对更改进行排队,您可以将它们存储为对类中方法的函数调用集。

    【讨论】:

    • 好吧,如果您想在之后添加不同类型的 mutators 并在您的 object 之外定义它们(它们可能是 流过滤器),我的方案通常会受益, 例如)。我假设如果我采取你所描述的方式,我将不得不改变类本身,看起来这不是合适的解决方案。
    • 实际上,这就是我必须将所有 mutator 内容添加到我的项目中的原因 :)
    • 是什么阻止您返回并添加新功能?如果所有修改其内部的类函数都与类本身保持一致,那么您最终会得到一个更简洁的解决方案吗?
    • +1 必须同意 Jon 的观点。你仍然需要修改你原来的类来让你的 InternalMutators 成为朋友。如果您打算这样做,不妨提供方法来可靠地更改提供它们的原始类中的内部结构。即使我不同意您的 mutator 设计,我认为如果您的所有 mutator 类只使用它们变异的对象提供的公共方法,至少会好很多。否则,您在本可以避免的地方存在紧密的数据耦合。
    猜你喜欢
    • 2017-09-24
    • 2023-03-12
    • 2011-11-22
    • 1970-01-01
    • 2010-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多