每当您设计软件时,您总是必须平衡不同的原则,因为其中许多是相互冲突的。例如,DRY(不要重复自己)原则经常与单一职责原则相冲突,特别是当两件事做相似但不完全相同的事情时。
很多时候,你必须决定哪个原则更重要,并强调那个原则而不是另一个原则(尽管你应该尽可能多地坚持)。很多时候,原则是一起工作的,有时它们会相互矛盾。
在这种情况下,Tell Don't Ask 与其他原则一起使用,例如Demeter 定律(尽管它的名称仍然是软件的原则,更好地描述为最少知识原则)。
LoD 告诉我们的是一个对象的方法应该只调用其他方法
- 就其本身
- 在作为参数传递给它的对象上
- 使用参数传递的对象创建/实例化的任何对象
- 对象直接组件对象
- 或者一个全局变量
没有具体说,但我觉得选择调用方法的优先顺序也应该是这个顺序,全局变量是最后的手段。但是,这既不是这里也不是那里。
因此,如果我们将 Tell, Don't Ask 与 LoD 结合使用,那么将对象传递给另一个对象进行“询问”是完全可以的。意思是,您有一个 Analysis 对象,您“告诉”它做某事,将 DataSet 对象作为参数传递。这就是遵守 TDA。在 Analysis 对象的方法中,您仅通过访问“亲密朋友”数据来遵守 LoD。
这也符合 SRP,因为您的 DataSet 仍然只是一个 DataSet 而您的 Analysis 对象是一个 Analysis 对象。
这里的关键是这些原则通常是“相对论的”。这意味着,从获取数据并想要执行分析的父对象的角度来看,您是在“告诉”分析对象做某事。
TDA 的目的是您的父代码不应查询您的 DataSet 的状态,然后根据它做出决定。相反,它应该将对象传递给其他对象并让这些对象执行它们的职责,这可能包括查询这些对象的状态,但这没关系,因为这是在它们的职责范围内。
此处进一步参考:
http://pragprog.com/articles/tell-dont-ask
编辑:
如果您想要更权威的来源,没有人比 Martin Fowler 本人更好(阅读到最后,您会找到此评论)
http://martinfowler.com/bliki/TellDontAsk.html
但就个人而言,我不使用告诉-不要-问。我确实希望将数据和行为放在一起,这通常会导致类似的结果。我发现tell-dont-ask 令人不安的一件事是,我看到它鼓励人们成为GetterEradicators,寻求摆脱所有查询方法。但是有时对象通过提供信息来有效地协作。一个很好的例子是接受输入信息并对其进行转换以简化其客户端的对象,例如使用 EmbeddedDocument。我已经看到代码陷入了只告诉适当负责的查询方法在哪里可以简化问题的卷积1。对我来说,告诉-不要-询问是共同定位行为和数据的垫脚石,但我不认为这是值得强调的一点