数据拉取与推送 OOP 方法
当我从头开始设计系统时,我经常面临一个困境:我的对象是否应该推送信息到另一个对象中,或者对象是否应该从另一个对象拉取必要的数据。
在 OOP 设计中是否有类似的标准,即我应该更喜欢由对象拉取数据,而不是将数据推送到对象中?
任何有经验的人都可以建议一下,从长远角度来看,或者当 OOP 结构/框架/图表变得更加复杂时,一种方法是否优于另一种方法?
When I design my system from scratch, I often face a dilemma whether my object should push information into another objects OR whether the objects should pull the necessary data from another objects.
Is there anything like a standard in OOP design, that I should prefer data pull by objects, versus data push into objects?
Can anyone experienced advise, whether one approach is better over the other from longer term viewpoint, or when the OOP structure/framework/diagram gets more complex?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
根据告诉不要问,推送更好 - 或者更多的OO。你不想查询对象的数据以便你可以做某事,你希望对象去做,因为他是知道他的数据的人。
有关邪恶吸气剂的相关文章
According to tell dont ask, push is better - or more OO. You don't want to query object for data so you can do something, you want object to do it, because he's the one who knows his data.
Related article about evil getters
我认为这里的讨论有点忽略了拉和推的关键点,而停留在个别例子和案例上。
推送:推送的优点是您了解自己的数据,并且知道您推送的内容。没有任何组件比拥有数据的组件更了解(或不应该了解)数据,这在理论上意味着更好的设计和更强大的系统。
拉动:我认为拉动方法的唯一优点是拉动的组件确切地知道它应该何时拉动。它可以在需要数据时启动对话,并且没有任何组件比需要数据的组件知道(或不应该知道)何时需要数据。
我对此的结论是:无论哪个组件拥有事务,它都会启动事务。如果您从 API 检索数据,显然 API 客户端将拥有该事务,因此将执行拉取操作。如果您正在广播一条消息,则广播者拥有该事务,因此它会进行推送。
I think the discussion here is kind of missing the crucial point about pulling and pushing and it is stuck on individual examples and cases.
Pushing : The advantage of pushing is that you know your data and you know what you are pushing. No component knows (or should not know) the data better than the component who owns the data, which will theoretically imply a better design and a more robust system.
Pulling : The only advantage I see in pulling approach is the component who pulls exactly knows when it should pull. It can initiate the conversation when it needs the data and no component knows (or should not know) when the data is needed than the component who needs it.
My conclusion on that is: whichever the component owns the transaction, it initiates the transaction. If you are retrieving data from an API, obviously the API client will own the transaction so will do a pull. If you are broadcasting a message than the broadcaster owns the transaction so it does a push.
正如其他答案所述,推或拉都不是更好,但您应该选择最适合您的设计需求的一个。
从此处讨论观察者模型是否应该基于推式或拉式:
对于这种模式,决定特征是数据变化的频率,然后是观察者希望接收该数据的相应速率。如果观察者想要的数据速度比主体生成数据的速度慢(例如手机上的 GPS,您不需要一直需要您的位置,只有当您有特定用途时才需要),那么轮询就是更有效率。如果观察者希望数据与主体生成数据的速度一样快(一个可能的例子是实时股票报价应用程序),那么推送通知可能会更好。
As stated by other answers, neither push nor pull is better, but rather you should pick the one that best fits your design needs.
From here discussing whether an observer model should be push or pull based:
For this pattern the determining characteristic is the frequency at which the data changes and then the corresponding rate at which the observers wish to receive that data. If the observers want the data at a slower rate than the subject generates the data (an example would be GPS on a phone, you don't need your position all the time, only when you have a specific use for it) then polling is more efficient. If the observers want the data as fast as the subject can produce it (a possible example would be a real-time stock ticker application), then push notifications are probably better.
在面向对象编程中它不应该有任何不同(可能有一些我错过的东西),但是拉动方法更好。
我之所以这么说是因为设计模式的最新趋势。 领域驱动设计和CQRS 是其中一些非常突出的,它们促进松散耦合,这是一件非常好的事情。
一个对象不应该关心另一个对象如何处理它的数据,可以说这不是它的责任。该对象应该只提供数据,然后需要数据的人应该从该对象中获取/拉出数据。看看事件驱动的设计。
它使对象独立于其他对象,并使其更加便携(不必更改它推入的位置,因为它将被拉出)。
TL;DR 我建议拉车而不是推车。
注意:所有这些不同的设计模式并不相互排斥,而是共存。
It should not be any different in OOP (there may be something i have missed) but a pull approach is better.
The reason I say this is because of the recent trends in design patterns. Domain Driven Design and CQRS being some of the very prominent, they promote loose coupling which is a very good thing.
A object shouldn't care what another object does with it's data, it is not it's responsibility so to speak. The object should only make the data available and then the ones needing the data should fetch/pull it from that object. Look at event driven design.
It makes the object independent of the other objects and makes it more portable (don't have to change where it pushes to, since it will get pulled from).
TL;DR I would recommend pull'ing over pushing.
NOTE: all these different design patterns dosen't exclude each other, but coexist.
target.Push(source)
source.Pull(destination)
通过查看您希望在代码中具有的依赖项来选择您的解决方案。
如果源和目标不能依赖于先前方案所需的内容,则您需要通过外部方法执行该操作知道(依赖于)源和目的地。但它只能公开访问两者。
如果您需要任何虚拟 ISource 来提供任何 IDestination,那么您需要这些接口来公开外部方法执行操作所需的所有方法。
如果单个外部方法无法对任何 ISource 和任何 IDestination 执行操作,那么您可能需要查看 Visitor 模式,Visitor 类对特定 Source1 和 SourceX Destination1 和 DestinationY 执行所有特定操作。
destination.Push(source)
source.Pull(destination)
Select your solution by looking at the dependencies you want to have in your code.
If Source and Destination cannot depend on what's needed for the previous scheme, then you need the action to be performed by an external method that knows (depends on) both Source and Destination. It only has public access to both though.
If you need any virtual ISource to feed any IDestination then you need those interfaces to expose all the methods needed for an external method to perform the action.
If a single external method cannot perform the action on any ISource and any IDestination, then you might want to look at the Visitor pattern, the Visitor class performing all the particular actions on the specific Source1 and SourceX Destination1 and DestinationY.
答案取决于您的架构目标,换句话说,没有通用的解决方案。
在客户端服务器架构中,您可能会在后端有一个分层系统,其中对象从其他对象中提取状态。这意味着只有某些“服务”最终会更新对象的状态。示例:创建一个新对象、更新对象的字段等(例如将新订单项添加到总订单中)。
在整体桌面应用程序中,情况可能完全不同。您可能会使用“模型-视图-控制器”变体和观察者模式等。在这种情况下,您将信息推送到 UI。
The answer depends on your architecture goals, in other words there is no general solution.
In a client server architecture you likely will have a layered system on the backend where objects pull state from other objects. That means only certain "services" will in the end update the state of an object. Example: creating a new object, updating a field of an object etc. (Like adding a new order item to the total order).
In monolithic desktop application it might be completely different. You likely use "Model-View-Controller" variations and observer patterns etc. In this case you push info e.g. to the UI.
通常“提取数据”意味着您正在执行 ajax 调用并在成功响应后运行回调。这还不错,但如果您要检查数据更新并因此每隔一定时间执行一次,则可能会过于密集。
但在在线 Web 应用程序的上下文中,替代方案是使用长轮询进行推送。由于长轮询与第一种方法没有太大不同,我建议您执行以下操作:
创建一个长轮询方法,从半公共推送 URL 端点(也称为 pubsub 的 Web 服务)提取数据,然后更新需要的所有内容通过在客户端中使用发布者-订阅者设计模式进行更新。这样您的更新就可以与数据源更加分离。
这是 IBM 就此主题编写的白皮书。 http://www.ibm.com/developerworks/library/specification/ws-发布订阅/
Usually 'pulling data' means you're doing an ajax call and running a callback upon its successful response. This isn't bad, but it can be overly intensive if you're checking for data updates and are thus doing it on an interval.
But in the context of an online web application, an alternative to this is push with long polling. Since long polling isn't terribly different from the first method, I propose you do the following:
Create a long polling method that pulls data from a a semi public push url endpoint (aka a webservice for pubsub), and then update everything that needs to be updated via using a publisher-subscriber design pattern in your client. That way your updates are more decoupled from the data source.
Here's a white paper that was written on this topic by IBM. http://www.ibm.com/developerworks/library/specification/ws-pubsub/
推/拉这个词是相对的。会有一个拥有数据的推送者,也会有一个需要数据的拉取者。如果我们实际上将数据存储在中立的位置而不是在推送器/拉取器内,那么会出现许多适合当时给定问题的可能性。一个在拥有数据时更新数据(如果需要,发送通知),另一个则拉取数据在他方便的时候获取数据。
许多设计模式(MVC、观察者、命令等)都可以用来处理该场景。
The word push/pull is relative. There will be a pusher who has data and there will be a puller who needs data. If we actually store the data in a neutral place and not inside push-er/pull-er, many possibilities raise that suits a given problem at time.One updates the data when he has it(send notification if necessary) and the other pulls the data at his convenience.
Many design patterns, MVC, Observer, Command, etc fall in place to handle the scenario.
首先,总的指导方针明确是:对象是数据和行为。通过提供对内部数据执行某些操作的方法,可以减少获取者的数量,从而减少拉取的次数。
单独的“推送更好”(在接受的答案中)并不能完全起作用,因为某些类中的推送操作可能需要对推送的对象进行新的拉动。相反,最佳实践应该是在最适合抽象的地方添加推送操作。这甚至可以导致新的更抽象的类/类的组合(请参阅面向对象的设计启发式,Riel,1996,第 37 页)。
First, the general guideline clearly is: objects are data and behavior. This encourages less getters and so less pulls by providing methods which do something with the internal data.
Alone "push is better" (in the accepted answer) can't quite work as a push-operation in some class can require a new pull at the pushed object. Instead the best practice should be adding the push operation where it fits the abstraction best. This can even lead to a new more abstract class / composition of classes (see Object-Oriented Design Heuristics, Riel, 1996, p. 37 f.).
从我的角度来看...作为使用 mvc 的桌面应用程序开发人员,存在一种微妙的平衡,即当模型对象可用时推送数据,然后根据模型中的逻辑(计时器/异步事件/通知),然后数据推送到控制器,然后推送到视图...ui 交互可以根据偏好进行任何一种方式,它们可以触发刷新或更新消息,告诉控制器需要执行某些操作,或者可以专门将数据推送到控制器,通常又是模型。
当然,这被现实世界的场景所简化和混淆,但只要有足够的资金来打算以特定的方式做到这一点就可以走很长的路。
From my perspective... As a desktop application developer using mvc, there is a delicate balence where by you push data when available to your model objects, then based on logic in the model (timers/ asynchronous events/ notifications) then the data is pushed out to the controllers and in turn to the view... The ui interactions can go either way depending on preference, they can fire a refresh or update message which tells the controller it needs to do something, or it can specifically push data into the controller and often in turn the model.
Of course this is simplified and confounded by real world scenarios but just having enough wherewithal to intend to do it a particular way can go a long way.
@kamil-tomsik 你对客户端服务器模型有什么看法,你有数百个作为观察者的客户端,但他们不需要相同的数据,所以如果你推送,你必须向他们发送你想要共享的所有数据,但其中一些人不需要它。不是会拖慢通讯速度吗?
@kamil-tomsik What do you think on a client server model, where you have hundreds of client who are observers, but they don't need same data, so if you push you have to send them all the data you want to share, but some of them, don't need it. Isn't it slow down the communication?
从设计的角度来看,数据拉动始终是更好的方法。原因是无论需要获取什么信息,您最好在返回这些值的类中创建函数,而不是推送信息,这并没有错,但在使用多态性和高级 OOP 概念时可能会使输出层次结构复杂化。希望这能回答您的问题。
From a design perspective, the data pull is always a better approach. The reason being that whatever information needs to be fetched, you're better off making functions in classes that returns those values instead of pushing information, which is not wrong but may complicate the outputs hierarchy when you are using polymorphism and advanced OOP concepts. Hope this answers your question.