保留整个物体VS不要寻找东西

时间:2012-05-04 23:07:00

标签: oop refactoring

我正在阅读福勒的重构书并看到Preserve Whole Object。一个不同的,更新的观点认为,这种重构与你应该做的完全相反:The Clean Code Talks - Don't Look For Things!

Fowler确实提到过你应该查看该方法是否可以移动到使用大型参数列表的类。我认为这将是唯一合理的选择。这种重构看起来像是一种定义不明确的方法的创可贴。

福勒的源材料有点陈旧。流行的智慧是让这种技术成为渡渡鸟的方式,还是在你想要进行这种重构的时候?或者我误解了测试驱动的风格,因为这些例子涉及对象构造,而不是消息发送?

2 个答案:

答案 0 :(得分:10)

面向对象设计中有许多概念,例如模式,原则和实践,起初可能看起来相似或相互矛盾。事实上,他们中的大多数既不相似也不矛盾。而使他们与众不同且一致的事情就是他们的意图。

清洁代码会谈视频中提到的保留整个对象重构和服务定位器模式之间的看似矛盾发生在它们被视为相同的概念时,尽管它们他们的意图和本质是不同的。

保留整个对象重构只是一种技术,通过减少函数的参数数量,使代码更易于阅读,理解和维护。另一方面,服务定位器是一种设计模式,用于使用控制反转概念管理系统中不同组件之间的依赖关系。与保留整个对象重构技术不同,该技术对系统具有局部影响(应用于系统的一小部分(函数)),服务定位器模式具有全局影响系统并解决更大的架构问题(依赖管理)。

何时使用“保留整个对象”重构?

当您有一个函数的两个或多个参数(基本上是一个对象的属性)时,使用保留整个对象重构,因此请传递该对象。

有一个类似的概念称为参数对象(又名参数对象)(Introduce Parameter Object refactoring),它表明如果你有一组参数不是一个对象的属性,但在概念上彼此相关或自然地一起使用,用自己的类包装它们,然后传递该类的实例。它主要用于向对象发送消息时。

引自清洁代码,第3章:函数,函数参数,第43页(Robert C. Martin):

  

参数对象

     

当一个函数似乎需要两个或三个以上的参数时,很可能会有一些   那些论点应该包含在他们自己的一类中。例如,考虑一下   以下两个声明之间的差异:

Circle makeCircle(double x, double y, double radius);
Circle makeCircle(Point center, double radius);
     

通过从中创建对象来减少参数的数量可能看起来像   作弊,但事实并非如此。当变量组一起传递时,方式为x和   在上面的示例中,它们可能是值得其名称的概念的一部分   自己的。

何时使用服务定位器模式?

当您的类具有非概念相关的依赖项并且您不希望您的类依赖于具体实现时,请使用服务定位器模式。实际上,这是您希望使用任何依赖关系管理方法的时候。另一种替代方法是依赖注入方法,它明确地将所有依赖项指定为构造函数的单独参数。而服务定位器传递单个容器对象中的所有依赖项。实际上,服务定位器模式与保留整个对象之间的相似性非常相似,即将单个对象中的参数组合起来作为混淆源。 依赖管理技术主要用于对象构建。

依赖管理的两种方法都有利弊,Martin Fowler撰写的Inversion of Control Containers and the Dependency Injection pattern文章对此进行了讨论。

何时同时使用?

有时会出现这样的情况:您的类将具有两个或多个概念相关的依赖项,您可能希望将它们组合在一个对象中,并使用服务定位器将其作为依赖项传递。所以,正如你可以看到这两个概念并不相互排斥。

答案 1 :(得分:0)

保留整个对象

专业人士

  • 使代码更短,更清晰。

缺点

  • 使界面更加复杂:

    void drawCircle(Point center, double radius);  
    // in order to understand this method I should study the Point class 
    

    而不是

    void drawCircle(double center_x, double center_y, double radius);
    // more verbose but makes explicit what you need to draw a circle
    
  • 在测试中产生样板代码,因为您需要创建和初始化虚拟参数对象:

    Point p = new Point(2,2); //boilerplate        
    drawCircle(p, 2);
    

    而不是

    drawCircle(2, 2, 2);
    
  • 创建额外的耦合,例如抽屉和点之间。

    有一个很好的比喻鼓励不这样做:你给收银员的钱,而不是你的钱包:)。

<强>摘要

如果方法需要大量数据,我会保留对象。在上面使用Point的示例中,我可能会这样做,因为Point非常原始。

否则我更喜欢直接传递必需的参数或使用"Introduce Parameter Object"模式来分组参数。