数据拉动与推动OOP方法

时间:2011-04-26 15:53:22

标签: oop design-patterns observer-pattern

当我从头开始设计我的系统时,我经常面临一个两难选择,即我的对象是否应该信息推送到另一个对象中,或者对象是否应该从另一个对象中拉出必要的数据对象。

在OOP设计中是否有类似标准的东西,我更喜欢按对象的数据拉动,而不是数据推入对象?

任何人都可以提出建议吗,一种方法是否比长期观点更好,或者当OOP结构/框架/图表变得更复杂时?

12 个答案:

答案 0 :(得分:23)

根据tell dont ask推送更好 - 或更多OO。您不希望查询对象的数据,因此您可以执行某些操作,您希望对象执行此操作,因为他是了解其数据的人。

Related article about evil getters

答案 1 :(得分:20)

正如其他答案所述,推或拉都不是更好,而是你应该选择最适合你设计需要的那个。

here讨论观察者模型是推送还是拉动:

  

谁触发更新?

     

主题与观察者之间的沟通已经完成   通过在observer接口中声明的notify方法。但它   可以从主题或观察者对象触发。通常是   当主体状态发生变化时,主体会触发notify方法。   但有时当更新频繁时连续发生变化   主题将确定许多不必要的刷新操作   观察者。为了使这个过程更有效,观察者   可以负责启动通知操作   认为必要。

对于这种模式,确定特征是数据改变的频率,然后是观察者希望接收该数据的相应速率。如果观察者希望数据的速度低于主体产生的数据(例如手机上的GPS,你不需要你的位置,只有当你有特定的使用时),然后轮询是更高效。如果观察者想要数据的速度与受试者能够产生的速度一样快(可能的例子是实时股票报价应用程序),那么推送通知可能会更好。

答案 2 :(得分:18)

我认为这里的讨论有点忽略了关于拉动和推动的关键点,它被困在个别的例子和案例上。

推送:推送的优势在于您了解自己的数据并知道自己在推动什么。没有任何组件比拥有数据的组件更了解(或不应该知道)数据,理论上这意味着更好的设计和更强大的系统。

拉动:我在拉动方法中看到的唯一优势是拉动的组件确切知道何时应该拉动。它可以在需要数据时启动对话,并且没有任何组件知道(或不应该知道)何时需要数据而不是需要数据的组件。

我的结论是:无论组件拥有什么交易,它都会启动交易。如果您要从API检索数据,显然API客户端将拥有该事务,因此将进行拉动。如果您正在广播一条消息而不是广播公司拥有该交易,那么它就会推送。

答案 3 :(得分:3)

在OOP中可能没有任何不同(可能有一些我错过了),但拉动方法更好。

我说这是因为最近的设计模式趋势。 Domain Driven DesignCQRS是非常突出的,它们促进松散耦合,这是一件非常好的事情。

一个对象不应该关心另一个对象对它的数据做了什么,这不是它的责任。该对象应该只使数据可用,然后需要数据的对象应该从该对象获取/拉取它。看看事件驱动的设计。

它使对象独立于其他对象并使其更具可移植性(不必更改它推送的位置,因为它将被拉出)。

TL; DR我建议拉过来推。

注意:所有这些不同的设计模式不会相互排斥,而是共存。

答案 4 :(得分:2)

目的地。的(源)

  • 目的地知道从源
  • 获取数据的内容和方法
  • 目的地必须依赖于来源,或
  • else Source必须实现提供的ISource接口并依赖于提供程序(可能是Destination包)
  • 该方法可直接私有访问Destination。

源。的(目的地)

  • 来源知道什么以及如何投入目的地
  • 来源必须依赖于目的地,或
  • else Destination必须实现提供的IDestination接口并依赖于提供程序(可能是Source包)
  • 该方法可以直接私有访问Source。

通过查看您希望在代码中使用的依赖项来选择您的解决方案。

如果源和目标不能依赖于前一个方案所需的内容,那么您需要通过知道(取决于)源和目标的外部方法执行操作。它只能公开访问这两者。

如果您需要任何虚拟ISource来提供任何IDestination,那么您需要这些接口来公开外部方法执行操作所需的所有方法。

如果单个外部方法无法对任何ISource和任何IDestination执行操作,那么您可能希望查看Visitor模式,Visitor类对特定Source1和SourceX Destination1和DestinationY执行所有特定操作。

答案 5 :(得分:1)

答案取决于您的架构目标,换句话说,没有通用解决方案。

在客户端服务器体系结构中,您可能在后端有一个分层系统,其中对象从其他对象中拉出状态。这意味着只有某些“服务”最终会更新对象的状态。示例:创建新对象,更新对象的字段等(例如,将新订单项添加到总订单中)。

在单片桌面应用程序中,它可能完全不同。您可能使用“模型 - 视图 - 控制器”变体和观察者模式等。在这种情况下,您可以推送信息,例如到用户界面。

答案 6 :(得分:1)

通常“提取数据”意味着您正在进行ajax调用并在成功响应时运行回调。这不错,但是如果您正在检查数据更新并且因此在一段时间内进行数据更新,则可能过于密集。

但是在在线Web应用程序的上下文中,替代方案是推动长时间轮询。由于长轮询与第一种方法没有太大差别,我建议您执行以下操作:

创建一个长轮询方法,从一个半公共push url端点(也就是pubsub的web服务)中提取数据,然后通过在客户端使用发布者 - 订阅者设计模式更新需要更新的所有内容。这样,您的更新就会与数据源脱钩。

这是IBM撰写的关于此主题的白皮书。 http://www.ibm.com/developerworks/library/specification/ws-pubsub/

答案 7 :(得分:1)

推/拉这个词是相对的。将会有一个拥有数据的推动者,并且会有一个需要数据的拉手。如果我们实际上将数据存储在一个中立的位置而不是在推送器/拉出器内,那么许多可能性会在一段时间内出现,以适应给定的问题。一旦有数据就会更新数据(必要时发送通知),另一个拉动他方便的数据。 许多设计模式,MVC,Observer,Command等都可以用于处理场景。

答案 8 :(得分:1)

首先,一般准则显然是:对象是数据行为。通过提供内部数据的方法,这可以减少吸引力,减少

单独"推动更好" (在接受的答案中)不能像某个类中的push-operation那样工作,可能需要对被推送的对象进行新的拉动。相反,最佳实践应该是在最适合抽象的情况下添加推送操作。这甚至可以导致一个新的更抽象的类/组合类(参见Object-Oriented Design Heuristics,Riel,1996,p.37 f。)。

答案 9 :(得分:0)

从我的角度来看......作为一个使用mvc的桌面应用程序开发人员,有一个微妙的balence,你可以在模型对象可用时推送数据,然后根据模型中的逻辑(定时器/异步事件/通知)然后数据被推送到控制器,然后推送到视图...... ui交互可以根据偏好进行,可以触发刷新或更新消息,告诉控制器它需要做什么,或者它可以具体将数据推送到控制器中,通常依次推送模型。

当然,这会被现实世界的情景所简化和混淆,但只要有足够的资金打算以特定的方式去做,这可能会有很长的路要走。

答案 10 :(得分:-1)

@ kamil-tomsik您如何看待客户端服务器模型,您有数百个客户端是观察者,但他们不需要相同的数据,因此如果您推送,则必须向他们发送您想要的所有数据分享,但其中一些,不需要它。是不是减缓了沟通?

答案 11 :(得分:-6)

从设计角度来看,数据拉动始终是一种更好的方法。原因是无论需要获取什么信息,最好在返回这些值而不是推送信息的类中创建函数,这不是错误的,但是当您使用多态和高级OOP概念时可能会使输出层次结构复杂化。希望这能回答你的问题。