在我参与的几个最近的项目中,我几乎沉迷于以下编码模式:(我不确定是否有适当的名称,但无论如何......)
假设某个物体处于某种确定状态,我们不想从外部改变这种状态。这些更改可能意味着任何行为,可以调用任何算法,但事实是他们专注于更改某些对象的状态(成员状态,数据状态等)。
让我们调用一种改变这些对象的离散方式Mutator
。 {em>(通常)一次应用Mutators
,并且它们有一些内部方法,如apply(Target& target, ...)
,它会立即引发更改对象的状态(实际上,它们是某种功能对象)。
它们也可以很容易地被同化为链并逐个应用(Mutator m1, m2, ...
);他们也可以使用BasicMutator
方法从一些基本的virtual void apply(...)
中获得。
我引入了名为InnerMutator
和ExplicitMutator
的类,它们在访问方面有所不同 - 首先它们也可以更改对象的内部状态,并且应该声明为朋友(friend InnerMutator::access;
)。
在这些项目中,我的逻辑转向以下列方式工作:
object
并将其设置为某个确定的状态foreach (mutator) mutator.apply(object);
现在问题。
这个方案可以很好地运行 (对我来说)似乎是一些非标准但有用的设计的样本 图案。
让我感到不舒服的是
InnerMutator
的东西。我没有 认为将变种人称为朋友 状态可能是的每一个对象 改变是一个好主意,我不想 找到合适的替代方案。可以用
Mutators
来解决这种情况,还是可以 建议一些替代模式 同样的结果?
感谢。
答案 0 :(得分:5)
我希望这不是冒犯性的,但我不禁认为这个设计对于一个相当简单的问题来说是一个过于花哨的解决方案。
例如,为什么需要聚合mutators?人们只能写:
template <class T>
void mutate(T& t)
{
t.mutate1(...);
t.mutate2(...);
t.mutate3(...);
}
有你的聚合变异器,只有它是一个依赖静态多态性的简单函数模板,而不是一个组成超级变异器的变换器组合列表。
我曾做过一些可能非常相似的事情。我制作了可由操作员和&amp;&amp;组合的功能对象。进入应用两个操作数的超级函数对象(按从左到右的顺序),以便可以编写如下代码:
foreach(v.begin(), v.end(), attack && burn && drain);
它非常整洁,当时对我来说似乎非常聪明,它非常高效,因为它可以动态生成新的函数对象(不涉及运行时机制),但当我的同事看到它时,他们认为我是疯。回想起来,我试图将所有内容都塞进功能样式编程中,这样有用但可能不应该过度依赖C ++。写起来很容易:
BOOST_FOR_EACH(Something& something, v)
{
attack(something);
burn(something);
drain(something);
}
虽然它代码更多,但它具有集中化和易于调试的优点,并且不会向使用我的代码的其他人引入外来概念。我发现它更有利于专注于严格的逻辑,而不是试图强制减少代码行。
我建议你深入思考这个问题并真正考虑是否继续使用这种基于mutator的设计是值得的,无论它多么聪明和紧张。如果其他人不能快速理解它,除非你有提升作者的权威,否则很难说服人们喜欢它。
对于InnerMutator,我认为你应该像瘟疫一样避免它。拥有外部mutator类可以直接修改类的内部结构,因为它们完全违背了很多内部的目的。
答案 1 :(得分:3)
简单地制作他们正在改变的类的Mutator
方法会不会更好?如果你想要几个类的常用功能那么为什么不让它们从同一个基类继承呢?这样做可以解决我想象的所有内心变异者的不适。
如果要排队更改,可以将它们存储为类中方法的函数调用集。