我开始编写一个流畅的界面,看看Martin Fowler在流畅的界面上写的一篇较旧的作品(我没有意识到他和Eric Evans创造了这个术语)。在这篇文章中,Martin提到setter通常返回正在配置或处理的对象的实例,他说这违反了CQS。
大括号世界中的常见惯例是修饰符 方法是无效的,我喜欢它因为它遵循的原则 CommandQuerySeparation。这个约定确实妨碍了 流畅的界面,所以我倾向于暂停这个惯例 情况下。
所以如果我的流畅界面做了类似的事情:
myObject
.useRepository("Stuff")
.withTransactionSupport()
.retries(3)
.logWarnings()
.logErrors();
这是否真的违反了CQS?
更新我打破了我的示例,将日志警告和错误显示为单独的行为。
答案 0 :(得分:9)
是的,确实如此。所有这些方法显然都返回了一些东西,同样显然它们有副作用(从你没有对返回值做任何事情的事实来判断,但你还懒得打电话给它们)。由于CQS的定义表明变异者不应该返回一个值,我们手中有明确的违规行为。
但是CQS被违反了吗?如果流畅的界面可以让你考虑所有事情,并且如果你认为它是一个众所周知的模式,具有同样众所周知的优点和缺点,为什么应该它是否违反了纸上的原则X?
答案 1 :(得分:3)
它在更改对象时违反了这个原则,但在它只返回一个新对象时却没有。
var newObject = myObject
.useRepository("Stuff")
.withTransactionSupport()
.retries(3)
.logWarningsAndErrors();
如果此语句后myObject
未更改,则一切正常。一般来说,如果且仅当它具有副作用时,流畅的界面违反了CQS原则。
但问题是,如果您的示例确实代表了一个查询。 “流利”是否一定意味着“查询”?它可能只是被视为一个动作流畅的界面,其中同一个对象从一个动作传递到下一个动作。
答案 2 :(得分:0)
没有。这里的模式是“配置”。此类配置命令将配置对象本身返回到与命令无关的内容。如果用于配置目的的命令返回了一些不相关的数据,则会违反命令/查询隔离,例如:
if (myObject.UseRepository("Stuff") > 1 && myObject.UseRepository("Bla") < 5) {
// oh, good, some invisible stuff internal to myObject is in right interval...
}
答案 3 :(得分:0)
我认为这取决于那些方法在做什么。如果每个命令都是自己的命令,那么可以,它可能会破坏CQS。
但是,您可以通过2种不同的方式轻松解决此问题。
仅不要链接命令。只需执行myObject.useRepository(“ ..”)。然后呼叫下一个,依此类推。但是,如果链中的下一个项目需要上一个项目的信息,那么您会遇到麻烦。
这些链接起来的事情不是直接使它们各自成为命令,而是直接在DTO上更新数据。然后最后,您运行一个名为.Configure()的方法,然后将该DTO发送到执行所有处理的单个命令。