Bob*_*Bob 16 oop single-responsibility-principle tell-dont-ask
我有一个案例,"告诉,不要问"似乎与"单一责任"原则相冲突.我已经查看了有关该主题的其他讨论,但尚未能够针对这种情况找出最合适的面向对象方法.
我有一个程序,可以读取和操作各种来源的数据集合.我创建了一个类来保存和操作数据("DataSet"类).它包括对数据集执行各种操作的方法,例如比较两个数据集以生成包含差异的新数据集,以及将数据集写入文件.
我现在想对数据集执行一些分析并将结果输出到报告中.我对编码的第一次尝试询问数据集从中提取信息,然后构建报告,但这似乎违背了"告诉,不要问"的原则.那么:我应该将分析方法放在DataSet类中,并告诉数据集分析自己并生成报告吗?这会违反单一责任原则吗?如果我希望将来执行其他类型的分析怎么办-DataSet类可能变得非常臃肿,有许多不同的分析例程,这与它的核心目的无关.
有谁能建议这里最好的方法?是否有解决此问题的特定设计模式?
Eri*_*sch 16
无论何时设计软件,您总是必须平衡不同的原则,因为它们中的许多都是冲突的.例如,DRY(不要重复自己)原则经常与单一责任原则冲突,特别是当两件事情相似但不完全相同时.
通常,您必须决定哪个原则更重要,并强调原则优于另一个原则(尽管您应该尽可能多地遵守原则).通常,原则一起工作,有时它们相互作用.
在这种情况下,Tell Do Not Ask可以使用其他原则,例如Demeter法则(尽管它的名称仍然是软件的原则,并且更好地描述为最少知识的原则).
LoD告诉我们的是对象的方法应该只调用其他方法
它没有具体说明,但我觉得选择调用方法的偏好顺序也应该按顺序排列,全局变量是最后的选择.但是,这既不是在这里也不是在那里.
因此,如果我们将Tell,Do not Ask with LoD结合起来,那么将对象传递给另一个对象以进行"询问"是完全可以的.意思是,你有一个Analysis对象你可以"告诉"做某事,将DataSet对象作为参数传递.这是坚持TDA.在Analysis对象的方法中,您只需访问"亲密朋友"数据即可遵守LoD.
这也符合SRP,因为您的DataSet仍然只是一个DataSet,而您的Analysis对象是一个Analysis对象.
这里的关键是这些原则通常是"相对论的".这意味着,从获取数据并想要执行分析的父对象的角度来看,您"告诉"分析对象要做某事.
TDA的目的是您的父代码不应该查询您的DataSet的状态,然后根据它做出决定.它应该将对象传递给其他对象并使这些对象执行其职责,这可能包括查询这些对象的状态,但这没关系,因为它是在他们的责任范围内.
进一步参考:
http://pragprog.com/articles/tell-dont-ask
编辑:
如果你想要一个更权威的来源,没有人比马丁福勒本人更好(读到最后,你会发现这个评论)
http://martinfowler.com/bliki/TellDontAsk.html
但就个人而言,我不会使用tell-dont-ask.我确实希望共同定位数据和行为,这通常会导致类似的结果.我发现令人不安的一件事就是告诉我不要问的是,我已经看到它鼓励人们成为GetterEradicators,试图摆脱所有的查询方法.但有时候,对象通过提供信息进行有效协作.一个很好的例子是获取输入信息并对其进行转换以简化其客户端的对象,例如使用EmbeddedDocument.我已经看到代码进入卷积只是告诉适当负责的查询方法将简化问题1.对我来说,告诉 - 不要问是一个共同定位行为和数据的垫脚石,但我认为这不值得强调