JavaHibernate:什么样的设计才能更好地摆脱强制转换

JavaHibernate:什么样的设计才能更好地摆脱强制转换,java,hibernate,casting,visitor,Java,Hibernate,Casting,Visitor,我使用Hibernate进行持久化 假设我有一个实体,其中包含有关文档的信息以及生成文档所需的信息(打印或通过电子邮件发送)。就这样, 这里的问题是DocumentInformation引用的是抽象类DocumentProductionConfiguration,而不是DocumentPrintConfiguration或DocumentEmailConfiguration的子类 因此,当我实际需要获得适当的配置时,我有两个选择:要么使用instanceof+casting,要么使用visit

我使用Hibernate进行持久化

假设我有一个实体,其中包含有关文档的信息以及生成文档所需的信息(打印或通过电子邮件发送)。就这样,

这里的问题是DocumentInformation引用的是抽象类DocumentProductionConfiguration,而不是DocumentPrintConfiguration或DocumentEmailConfiguration的子类

因此,当我实际需要获得适当的配置时,我有两个选择:要么使用instanceof+casting,要么使用visitor模式欺骗Java,以便它在运行时真正理解它正在处理的配置

  • 使用铸造:

    public class XmlBuilder{
    public XMLMessage buildXmlMessage(DocumentInformation documentInformation){
        if(documentInformation.getDocumentProductionConfiguration() instanceOf DocumentPrintConfiguration){
            DocumentPrintConfiguration printConfig = (DocumentPrintConfiguration) documentInformation.getDocumentProductionConfiguration();
            XMLMessageConfig xmlConfig = handlePrintConfig(printConfig);
        }
     }
     public XMLMessageConfig handlePrintConfig(DocumentPrintConfiguration printConfig){
        ....build that XMLMessageConfig....
     }
    }
    
  • 使用访客模式:

  • 我需要为XmlBuilder添加一个新接口来实现

    public interface XmlBuilderVisitor<T> {
        T handlePrintConfig(DocumentPrintConfiguration printConfig);
    }
    public class XmlBuilder implements XmlBuilderVisitor<XMLMessageConfig> {
        @Override
        public XMLMessageConfig handlePrintConfig(DocumentPrintConfiguration printConfig){
            ....build that XMLMessageConfig....
         }
        public XMLMessage buildXmlMessage(DocumentInformation documentInformation){
            XMLMessageConfig xmlMessageConfig = documentInformation.getDocumentProductionConfiguration().buildConfiguration(this);
        }
    }
    public abstract class DocumentProductionConfiguration{
        public abstract <T> T buildConfiguration(XmlBuilderVisitor<T> visitor);
    }
    public class DocumentPrintConfiguration extends DocumentProductionConfiguration{
        public <T> T buildConfiguration(XmlBuilderVisitor<T> visitor){
            return visitor.handlePrintConfig(this);
        }
    }
    
    公共接口XmlBuilderVisitor{
    T handlePrintConfig(DocumentPrintConfiguration printConfig);
    }
    公共类XmlBuilder实现XmlBuildServiceSitor{
    @凌驾
    公共XMLMessageConfig handlePrintConfig(DocumentPrintConfiguration printConfig){
    ..构建XMLMessageConfig。。。。
    }
    公共XMLMessage buildXmlMessage(文档信息文档信息){
    XMLMessageConfig XMLMessageConfig=documentInformation.getDocumentProductionConfiguration().buildConfiguration(此);
    }
    }
    公共抽象类DocumentProductionConfiguration{
    公共抽象BuildT配置(XMLBuildServiceSitor访问者);
    }
    公共类DocumentPrintConfiguration扩展了DocumentProductionConfiguration{
    公共BuildT配置(XMLBuildServiceSitor访问者){
    return visitor.handlePrintConfig(此文件);
    }
    }
    
    这两种解决方案都有点。。。第一个是因为它违反了开闭原则(我需要始终维护这些ifs…)

    从这个意义上讲,第二个更好:一旦您添加了新的配置,编译器将引导您完成整个过程:首先,您需要在配置本身中实现适当的方法,然后在所有访问者类中实现。另一方面,我基本上是在向实体传递服务,这相当尴尬


    所以我觉得我是在治疗症状而不是问题。也许设计本身需要一些改变?但我不确定如何改进…

    我建议将“句柄”功能推到
    文档生产配置和子类中。因此
    DocumentPrintConfiguration
    将包含一个
    handle
    函数,该函数构建并返回
    XMLMessageConfig
    。然后,您的XmlBuilder变成:

    public class XmlBuilder{
        public XMLMessage buildXmlMessage(DocumentInformation documentInformation){
            XMLMessageConfig xmlConfig = documentInformation.getDocumentProductionConfiguration().handle();
        }
    }
    

    我建议将“句柄”功能推入
    DocumentProductionConfiguration
    和子类。因此
    DocumentPrintConfiguration
    将包含一个
    handle
    函数,该函数构建并返回
    XMLMessageConfig
    。然后,您的XmlBuilder变成:

    public class XmlBuilder{
        public XMLMessage buildXmlMessage(DocumentInformation documentInformation){
            XMLMessageConfig xmlConfig = documentInformation.getDocumentProductionConfiguration().handle();
        }
    }
    

    不幸的是,您的问题是:您使用java。Java远远不是完美的语言,有时你不得不使用一些肮脏的技巧。我会使用一个库,将所有东西完全抽象出来,而不必去想这些无聊的事情。我最终会得到
    objectMapper.toXML(myDocumentInformation)(作为一个例子),可以专注于更重要的设计问题。不幸的是,您的问题是:您使用java。Java远远不是完美的语言,有时你不得不使用一些肮脏的技巧。我会使用一个库,将所有东西完全抽象出来,而不必去想这些无聊的事情。我最终会得到
    objectMapper.toXML(myDocumentInformation)(作为一个例子),可以专注于更重要的设计问题。