该问题主要是设计问题(与 ddd 有点相关)。很抱歉这个人为的例子:
假设,您有代表不同类型水果的(域)类:苹果、樱桃等。现在假设你必须实现一些压榨果汁的行为。调用者应该能够在不知道他得到哪种特定水果的情况下调用挤压。
我应该把这种行为放在哪里?
当然,可以定义一个水果接口/基类函数
Fruit#squeeze()
并让所有子类实现自己的行为。现在调用者可以简单地做这样的事情:
Fruit f = new Cherry();
f.squeeze();
但是,如果挤压不是那么简单并且涉及更复杂的行为,比如调用不同的外部服务,每个水果都有不同的服务,应该怎么办?
AppleJuicerService#squeeze(Apple a)
和
CherryJuicerService#squeeze(Cherry c)
? 从域类调用服务感觉不对。
我读过似乎不适合这里的双重调度模式,因为每个子类都需要不同的服务。
我的问题是:在这里可以做些什么来获得“干净”的设计?
编辑:
感谢您迄今为止的所有回答。我会试着澄清一下这个问题。对于我在这里要说明的问题,我将尝试给出另一个希望不那么做作的示例:
考虑一个 Message 基类,它允许将其内容显示为字符串。
interface Message {
String showContent();
}
现在假设我们有不同类型的消息,例如 EMailMessage:
class EMailMessage implements Message {
//some specific parameters for email
private EmailAddress recipientEmail;
public String showContent() {
//here the content would be converted to string
return "the content of an EMail"
}
}
另一种类型是 SMSMessage:
class SMSMessage implement SMSMessage {
//some specific parameters for SMS
private TelNumber recepientTelephoneNumber;
public String showContent() {
//here the content would be converted to string
return "the content of a SMS"
}
}
此外假设,消息被建模为实体,因此可以保存在数据库中。尽管从技术上讲,假设某些依赖注入框架(如 Spring)用于注入依赖项。
与水果示例类似,考虑我们必须实现一个 send() 行为,该行为将消息发送给接收者。此外,假设发送电子邮件涉及与 SMS 不同的逻辑。现在,问题是:应该将发送消息的逻辑放在哪里?
通常我会选择创建一个用于发送 SMS 的服务,例如它会封装 SMS 服务提供商的 API。此外,我将创建另一个服务来封装发送电子邮件。
interface SendMessageService<T extends Message> {
void send(T message);
}
class SendEmailService extends SendMessageService<EMailMessage> {
public void send(EMailMessage message) {
//send the EMail
}
}
class SendSMSService extends SendMessageService<SMSMessage> {
public void send(SMSMessage message) {
//send the SMS
}
}
这种方法的缺点是您不能在没有确定其具体子类的情况下发送消息,即无法直接执行以下操作
List<Message> messages = //Messages of different types
SendMessageService service = //???
for (Message m : messages) {
service.send(m);
}
当然,可以根据特定类型的消息创建一个用于创建服务的工厂。但这在某种程度上意味着克隆 Message 的继承层次结构。有没有更好的方法来达到预期的结果?还是我错过了什么?或者以某种方式将服务注入实体会更好吗?