0

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

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

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

它们也可以很容易地被同化成并一个一个地应用(Mutator m1, m2, ...);它们也可以从一些基本BasicMutator的 withvirtual void apply(...)方法中派生出来。

我已经介绍了被调用的类InnerMutatorExplicitMutator它们在访问方面有所不同——首先它们也可以改变对象的内部状态,并且应该被声明为友元(friend InnerMutator::access;)。


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

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

现在的问题。

该方案运行良好,并且 (对我而言)似乎是一些非标准但有用的设计模式的示例。

让我感到不舒服的是那些InnerMutator东西。我不认为将 mutator 声明为每个可以更改状态的对象的朋友是一个好主意,我不想找到合适的替代方案。

这种情况可以解决Mutators吗?或者您可以建议一些具有相同结果的替代模式吗?

谢谢。

4

2 回答 2

5

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

例如,为什么需要聚合 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 类完全违背了拥有内部的许多目的。

于 2010-06-28T18:01:44.340 回答
3

Mutator简单地制作他们正在改变的类的那些 s 方法不是更好吗?如果您希望多个类具有共同的功能,那么为什么不让它们从同一个基类继承呢?这样做将处理我想象的所有内部突变体不适。

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

于 2010-06-28T17:53:25.763 回答