命令查询分离

2005 年 12 月 5 日

术语“命令查询分离”是由 Bertrand Meyer 在他的著作“面向对象软件构造”中提出的 - 这本书是 OO 早期最具影响力的 OO 书籍之一。(第一版影响很大,第二版也不错,但你需要在健身房锻炼几个月才能把它举起来。)

基本思想是,我们应该将对象的方法分成两个截然不同的类别

  • 查询:返回结果,不改变系统的可观察状态(没有副作用)。
  • 命令:改变系统状态,但不返回值。

由于术语“命令”在其他上下文中被广泛使用,我更喜欢将它们称为“修改器”,你也会看到术语“变异器”。

这个原则中真正有价值的想法是,如果你能清楚地将改变状态的方法与不改变状态的方法分开,这将非常方便。这是因为你可以在许多情况下更自信地使用查询,在任何地方引入它们,改变它们的顺序。你必须对修改器更加小心。

该原则中的概念是,返回类型是区分两者差异的关键。这是一个很好的约定,因为大多数情况下它都能很好地工作。考虑一下在集合中迭代的 Java 习惯用法:next 方法既返回集合中的下一个项目,又推进迭代器。我个人更喜欢一种有单独的 advancecurrent 方法的风格。

Meyer 喜欢绝对地使用命令查询分离,但也有例外。弹出堆栈就是一个修改状态的查询的例子。Meyer 正确地说你可以避免使用这种方法,但它是一个有用的习惯用法。因此,我更喜欢在可能的情况下遵循这个原则,但我准备打破它来获得我的弹出操作。

如果语言本身能够支持这个概念就好了。我可以想象一种语言,它可以检测状态改变方法,或者至少允许程序员标记它们。语言无法自动检测它们的原因之一是,关于不改变状态的规则实际上只适用于系统的可观察状态。使用程序员标记似乎更合理,但很少见。我真正遇到的唯一情况是 C++ 中的 const 修饰符。由于我已经很多年没有使用 C++ 了,所以我很难评估它在实践中的有用性。我的感觉是,优秀的 C++ 程序员会大量使用 const 并喜欢它。