Java Hibernate: что будет лучшим дизайном, чтобы избавиться от кастинга

Я использую Hibernate для настойчивости.

Предположим, у меня есть объект, который содержит информацию о документе и необходимую информацию для его создания (либо печать, либо отправка по электронной почте). Именно так: введите описание изображения здесь

Проблема здесь заключается в том, что DocumentInformation содержит ссылку на абстрактный класс DocumentProductionConfiguration, а не на подклассы DocumentPrintConfiguration или DocumentEmailConfiguration.

Поэтому, когда мне действительно нужно получить подходящую конфигурацию, у меня есть два варианта: либо использовать instanceof + casting, либо использовать шаблон посетителя, чтобы обмануть Java, чтобы он фактически понимал во время выполнения, с какой конфигурацией он имеет дело.

  1. Используя кастинг:

    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....
     }
    }
    
  2. Использование шаблона посетителя:

Мне нужно добавить новый интерфейс для 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);
    }
}

Оба эти решения вроде как... Первое, потому что оно нарушает принцип открытого-закрытого (мне нужно всегда поддерживать эти ifs...).

Второй в этом смысле лучше: как только вы добавите новую конфигурацию, компилятор проведет вас через процесс: сначала вам нужно будет реализовать соответствующий метод в самой конфигурации, а затем во всех классах посетителей. С другой стороны, довольно неловко, что я в основном передаю служение сущности...

Поэтому я чувствую, что лечу симптомы, а не проблему. Может быть, сам дизайн нуждается в некоторых изменениях? Но я не уверен, как это можно улучшить...

1 ответ

Я бы порекомендовал толкать функциональность "ручки" в DocumentProductionConfiguration и подклассы. Таким образом DocumentPrintConfiguration будет содержать handle функция, которая строит и возвращает XMLMessageConfig, Тогда ваш XmlBuilder становится:

public class XmlBuilder{
    public XMLMessage buildXmlMessage(DocumentInformation documentInformation){
        XMLMessageConfig xmlConfig = documentInformation.getDocumentProductionConfiguration().handle();
    }
}
Другие вопросы по тегам