我的项目中有以下层次结构:
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)而不是 handle(SubParsedFailedMessage msg)作为强调文本期待..
有谁能说为什么多态在这里不起作用?
答案 0 :(得分:2)
doHandle接收AbstractMessage类型的参数。这意味着在编译代码时,为handle()调用生成的代码会生成调用句柄(AbstractMessage),而不是处理(ParseFailedMessage)。
如果您仍希望根据对象的动态类型调用函数,则应将该函数作为SubParsedFailedMessage的成员,并调用messageToHandle.handle()。这也看起来更像OOP,因此是首选。
答案 1 :(得分:2)
Eran对问题原因的解释是正确的,方法重载在编译时进行评估。
在考虑了一段时间之后,我想出了一个可能的解决方案。
此问题的一个解决方案是访问者设计模式:
您需要一个界面,称之为MessageHandler
,定义您的handle()
方法。
在AbstractMessage上放置一个抽象的dispatch(MessageHandler handler)
方法,以及一行代码的实现,如此
public void dispatch(MessageHandler handler) {
handler.handle(this)
}
每条消息中都有。这意味着编译器将获得有关在编译时调度方法调用的位置和正确分派的信息。作为重构步骤,AbstractMessage
实施MessageHandler
。之后,这可以在其自己的课程中加以考虑。
附带好处: 您的消息处理代码将与消息定义分开,您可以使用不同的单元测试或不同的用例替换消息处理程序。
缺点:
对于要以这种方式分派的每种消息类型,消息处理程序接口都需要一个抽象的handle()
方法。