1

我的项目中有以下层次结构:

public abstract class AbstractMessage extends AbstractEntity{}
public class ParseFailedMessage extends AbstractMessage {}
public class SubParsedFailedMessage extends ParseFailedMessage {}

我有以下方法:

public AbstractMessage doHandle(AbstractMessage messageToHandle) {

   //prepareToHandle(messageToHandle);

   handle(messageToHandle);

   //finalize(messageToHandle);

   return messageToHandle;

}

@Transactional(readOnly = false)
private void handle(ParseFailedMessage message) {

   message.setHandled(false);

}

@Transactional(readOnly = false)
private void handle(AbstractMessage message) {

   message.setHandled(true);

}

出于某种原因,当我调用 doHandle(new SubParsedFailedMessage()) 时,从中调用的函数是句柄(AbstractMessage msg) 而不是句柄(SubParsedFailedMessage msg),因为强调的文本是预期的。

谁能说为什么多态在这里不起作用?

4

2 回答 2

2

doHandle 被声明为接收 AbstractMessage 类型的参数。这意味着当你的代码被编译时,为调用handle()而生成的代码被生成为调用handle(AbstractMessage),而不是handle(ParseFailedMessage)。

如果您仍然希望根据对象的动态类型调用函数,则应将该函数设为 SubParsedFailedMessage 的成员,并调用 messageToHandle.handle()。这看起来也更像 OOP,因此是首选。

于 2013-05-18T21:28:31.933 回答
2

Eran 对问题原因的解释是正确的,方法重载是在编译时评估的。

经过一段时间的思考,我想出了一个可能的解决方案。

此问题的一种解决方案是访问者设计模式:

您需要一个接口,调用它MessageHandler来定义您的handle()方法。

在 AbstractMessage 上放置一个抽象dispatch(MessageHandler handler)方法和一个像这样的一行代码的实现

public void dispatch(MessageHandler handler) {
    handler.handle(this)
}

在每条消息中。这意味着编译器将获得有关在编译时在何处分派方法调用并正确分派的信息。作为重构步骤,说AbstractMessage实现MessageHandler. 稍后可以将其分解为自己的类。

附带好处:您的消息处理代码将与您的消息定义分开,您可以将消息处理程序替换为不同的单元测试或不同的用例。

缺点:消息处理程序接口需要一个抽象handle()方法,用于您希望以这种方式分派的每种消息类型。

于 2013-05-19T09:21:35.440 回答