【问题标题】:Objects which send themselves - a good idea?发送自己的对象 - 一个好主意?
【发布时间】:2010-09-10 15:22:49
【问题描述】:

将对数据进行操作的函数移到包含该数据的类中时,您在哪里划线?例如,假设您有一个简单的类,其中存储了天气描述,其中包含温度、湿度、风速和风向以及进行测量的时间等变量。现在想象你有一个这个类的对象,你想把它传输给其他人——另一个进程,另一台机器,等等。您是否将用于将对象传输到对象本身的代码 - 例如,通过向简单数据类添加 Send(destination-type) 方法?或者你是否将这种特性保存在可以通过介质发送和接收任何东西的单独类中——无论是网络、文件 i/o、进程间通信还是类似的东西?

我的直觉是让我的数据类保持简单,并在我想传输它们时将它们包装起来——在将它们序列化并以他们理解的简单接口呈现发送者和接收者类的类中。另一种选择似乎是将包括厨房水槽在内的所有内容都放入简单的数据类中——每个可能对该数据进行操作的函数,无论多么间接。简而言之,在我看来,网络错误处理代码不属于简单的数据类。

这对我来说似乎很明显,但我不断看到开发人员将 Send() 方法放在他们的类中。他们甚至将 message 类告诉 Send() 自己,这对我来说似乎非常违反直觉;如果我在一张纸上写一封信,我不会让纸自己发送。我把信包在一个信封里递给邮递员,因为他有一辆面包车和一张地图。人们怎么看?

【问题讨论】:

标签: oop class data-structures


【解决方案1】:

有效载荷项目本身的逻辑是:现在风速是多少?

解释这些数据是有逻辑的:我们现在可以停靠这艘船了吗?

决定将有效载荷发送到某个地方是有逻辑的:哦,这是一个新的天气值,那里有人在乎。

然后是实际的网络内容。

有效负载可能需要能够自行序列化和反序列化。我认为其余的都不是有效载荷的问题。 Send() 必须有一个更好的地方。尤其是因为您可能会选择一次发送多个有效负载对象,并且它们不能全部相互发送。

【讨论】:

    【解决方案2】:

    这不是一个简单的问题。我使用这两种方法完成了项目,总体而言,我更喜欢使用“智能模型”方法,其中模型非常了解如何使用自己的数据做事。

    导致良好封装的原则之一是“告诉,不要问”——如果你告诉类对自己做某事,那么除了类本身之外没有人需要知道类的内部表示。这绝对是一件好事。此外,我发现将逻辑放入类本身通常会使代码重用变得更容易——当其他人使用该类时,他们会很快发现它已经知道如何执行给定的操作。

    但是,我不希望这导致我的应用程序层之间的界限被打破。我不希望业务对象知道如何将自己表示为 HTML——这是一个表示问题。所以在这种情况下,我会说这个类应该知道如何以某种规范的方式表示自己,但它不应该知道网络的东西。实际的发送函数应该属于一个服务。

    【讨论】:

    • 当您说“类应该知道如何以某种规范方式表示自己”时,您的意思是指它的属性的其他规范方式吗?
    • @Mark -- 我不确定。例如,一个类知道如何将自己序列化为 XML 可能是有意义的,但在现实世界中,我经常发现在不同的情况下我需要稍微不同的 XML 表示,这似乎更像是一个表示问题。
    • 一般来说,演示文稿确实不应该是持有数据的类的关注点。如果您的 XML 序列化与演示相关,我会考虑将其放在其他地方...
    【解决方案3】:

    在我的职业生涯中,我曾多次在此类设计问题上反复讨论过。现在,我似乎在你所在的地方,主要是因为我在当前的生活中做了很多 SOA,我最终编写了很多只存在于序列化进出各种 over-the- 的类有线格式,主要涉及 XML 和 JSON。

    当您进入“服务”世界时,类通常只是来回发送的数据的表示。因此,我通常将我的类分成两个逻辑桶,“保存数据的类”和“做事的类”。我不知道我是不是唯一一个做这种事情的人,但这就是我所在的地方。

    【讨论】:

      【解决方案4】:

      简短的回答是,这取决于您要处理的下游影响。

      一般来说,当有两种方式做某事时,通常意味着两种方式都有其优点。脑海中浮现出几个例子(SQL 与 NoSQL、自动与手动传输、交流与直流、客户端与服务器端等)。这样做的结果是,你一定会得到很多双方都有意见的人。

      所以你提出的问题是一个对象什么时候可以操纵它自己的数据,什么时候我需要把它分离出来。

      我个人更喜欢保持简单的数据结构,其主要职责是保持数据的一致性。操作或使用这些数据的责任将是其他类的责任。这倾向于帮助我将政策和实施分开。例如,如果我想实现一个缓存策略,我只需要访问获取数据的层,而不是存储或操作数据的对象。

      另一方面,这确实使 API 更难使用,因为东西在哪里并不总是很明显。这也产生了在多个位置创建相同策略的可能性(并且每一层最终都实现了一些缓存)

      例如,如果在 String 类中不容易找到 Split、Join 和 Substring 等 String 方法,而是在其他地方,例如假设的 Parse 类,那么在我找到这个假设的 Parse 类之前,我可能会有编写了这些方法的多个糟糕版本。一个现实生活中的例子是,人们编写了与 Math 类中的方法相同的方法,因为他们不知道。

      最后,如果您不想处理更改 Send 方法的工作方式可能需要访问大量类的下游影响,请将其移到类之外

      如果您不想处理那些意外实现了自己的 Send 方法的人,并且您不想一直强化它,那么最好将其放在 类中。 p>

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-02-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-07
        • 2015-09-30
        • 2016-04-10
        相关资源
        最近更新 更多