这个问题可能会征求辩论和/或争论,所以如果它被关闭,我认为这个问题的答案将是:它取决于。但希望这个问题可以用一个很好的理由来回答,而选择一个设计决策而不是另一个。
当我查看this answer时,对于有关OOP的问题,我突然意识到我有时会问这个问题。
我们假设,项目的要求和技术性允许您选择以下任一选项:
选项a:
$service = new SendService();
$recipient = new Recipient( 'John', 'Doe', 'john.doe@example.com' );
$message = new Message( $service );
$message->setContent( 'Lorem ipsum...' );
$message->send( $recipient );
换句话说:让消息在内部与内部通信 服务,让它将收件人和自己传递给服务。
选项b:
$service = new SendService();
$recipient = new Recipient( 'John', 'Doe', 'john.doe@example.com' );
$message = new Message();
$message->setContent( 'Lorem ipsum...' );
$service->send( $message, $recipient );
换句话说:让客户端代码将消息(和收件人)传递给 服务。
是否有任何特定(设计)理由选择一个而不是另一个,或者这只是一个偏好问题?
在这种特殊情况下,我认为后一种选择更类似于向邮局发送邮政卡的真实例子,而不是将邮局塞进邮政卡,如果你得到我的漂移。因此选择该选项更有意义。或者现实生活中的隐喻不能证明设计选择的合理性?
答案 0 :(得分:5)
正如我所看到的,用例可以恢复为:
我有
message
和message service
。我需要发送message
以某种方式使用message service
替代方案是:
A -
message
知道message service
并知道如何发送 本身。
和
B -
message
不知道message service
。message service
收到message
并发送。
正如我所看到的,在第一种情况下,这样的事情正在发生声纳或更晚(伪代码):
Message {
send(MessageService) = {
// Do lot's of stuff.
MessageService.send(this)
}
}
那么,为什么不首先选择B
选项呢?
答案 1 :(得分:4)
$message = new Message( $service );
这很有道理。您强制您的用户预先声明特定服务将使用给定的消息。通常,消息不需要知道它正在发送的服务。但是,服务人员需要知道该消息。
你实际上限制了你的灵活性,几乎没有收获。如果您想通过电子邮件发送它,但如果它失败了,您希望能够将其假脱机到将重试的服务。你想写:
$message = new Message($emailService);
if (!$message->send()) {
$message2 = new Message($spoolService);
$message2->clone($message);
$message2->send();
}
或者:
$message = new Message();
if (!$email->send($message)) {
$spooler->send($message);
}
如果您正在编写该假脱机程序,并且您希望保留这些消息并将其读回来,该怎么办?现在您的读者也需要了解您的服务,以便能够首先创建消息等。通常,消息是一个自包含的对象 - 保持这种方式。
我个人无法想象做出选择的唯一可靠理由。
答案 2 :(得分:3)
相对于此合同需要最少自由的人应该接收另一个。通常,在具有数据对象和服务的情况下,服务应该接收数据对象。但不总是。特别是,在动态链接操作的应用程序中,例如,作为Function对象,您将希望Message接受要执行的操作。
如前所述,在消息的构造函数中传递服务毫无意义。但我担心这不是你要问的问题 - 换句话说,我认为你可能“应该”写下来了
$message->send( $service, $recipient );
保持苹果和苹果。
考虑的关键自由度是可测试性。
有时答案是“不” - 需要第三类来封装发送操作的特定实例。
答案 3 :(得分:1)
嗯,我确实认为这可能是一个悬而未决的问题,除非你有特定的情况;但它并非完全开放。就个人而言,我认为除非你有特定的技术理由这样做,否则没有特别的理由打破服务对象的隐喻;但是,没有严格的规则,你不能做消息发送自己的事情。 (事实上,它让我想起了我刚读完OO时我读过的一些早期例子。)
但是,请注意,您可能有技术理由这样做。比如说,您的应用程序有几个Service
可能会发送Message
,具体取决于将特定客户端系统映射到特定服务的配置。客户没有特别的理由需要知道有关服务细节的任何信息,客户真正需要做的唯一事情是撰写邮件并将其发送出去。也许这甚至已经大部分实现,只是消息只是由每个组件记录,而不是通过服务发送,而且它是一个生产系统,你需要对系统进行绝对最小的更改。或许这可能是团队认为更好的系统隐喻。
因此,客户端系统从某种Message
对象请求MessagingFacade
,该对象实例化Message
,为其提供Service
的引用,并传递给它给客户。然后,客户端可以随心所欲地执行任何操作,例如,将其传递到系统的多个不同部分以整理状态信息,系统的任何特定部分可能是写出Message
的终端点。取决于系统状态和日志记录级别,并且您希望终端实体能够发送它而不需要(或允许)可能是发送者的所有类来了解MessagingFacade
。
在这样的情况下,我觉得Message本身实现Send动词似乎是合理的,这样消息编写者就可以完成消息并调用theMessage.Send
。
所以,尽管事实上对于这样的事情可能存在“经验法则”,但编写现实生活系统的一部分是认识到打破这些规则是可以的,特别是当遵循“正常”规则最终打破隐喻时您系统中的其他位置。这个问题的答案,就像许多“哪个更好”的问题一样,总是:在我的特殊情况下有什么意义?一个或另一个是否简化了我系统的其他部分?一个或另一个是否破坏了我系统中已实现部分的任何假设?等等。 :)
所以:
“是否有任何特定(设计)理由选择其中一个,或者这只是一个偏好问题?”
我认为答案是:我们没有足够的信息来决定。任何设计原因都取决于您系统的详细信息。如果我们假设,在你的论述中,两个选择之间确实没有技术差异,那么我认为我会采用传统的服务发送信息的观点,但我也认为有一个论点朝另一个方向发展。如果我们让消息自己发送,我们减少了系统中的耦合;最初发送消息的所有内容(可能是很多类)都必须知道Message
和Service
,而我们只增加Message
和Service
之间的耦合(只是那些课程)。
“在这种特殊情况下,我认为后一种选择更像是将邮政卡发送到邮局的真实例子,而不是将邮局塞进邮政卡,如果你得到我的漂移那么选择那个选项更有意义。或者做现实生活中的隐喻不能证明设计选择的合理性?“
我想说现实生活中的隐喻并不是 in and their of their 来证明设计选择的合理性。它们只能在系统模型对现实生活进行密切建模的情况下证明其合理性。这里很难给出一般性答案,因为有太多现实生活中的隐喻,以及实现系统的许多可能方法。在任何特定的情况下,你可以争论是否对现实世界进行建模是正确的决定,但在摘要中,有太多的例外可以给出一个坚定的答案。