JPA, наследование и instanceof - PullRequest
5 голосов
/ 10 июня 2011

Я использую наследование JPA со стратегией JOIN (JPA2 / Hibernate).У меня есть абстрактная общая сущность Event с общими полями (дата, время, место и т. Д.) И ее дочерние элементы, скажем, OutdoorEvent, ClassicalMusicEvent и т. Д. С конкретными полями для каждого типа.Я делаю поиск по всем событиям, получая List<Event>, который я показываю.Обработка для каждого типа события отличается, поэтому мне нужно выяснить тип события для каждого объекта Event.Теперь вот проблема.Я придумал два решения.Во-первых, ключевое слово instanceof:

if (event instanceof OutdoorEvent) {
   ...
} else if (event instanceof OtherKindOfEvent) {
   ...
} etc.

Во-вторых, я добавляю временное поле enum к сущности Event и задаю это поле в конструкторе каждого дочернего типа.Тогда я мог бы сделать:

if (event.getType() == EventType.OutdoorEvent) {
   ...
} else if (event.getType() == EventType.OtherKindOfEvent) {
   ...
} etc.

Какое решение лучше или больше ООП?Есть ли другое решение для этого?

Ответы [ 4 ]

4 голосов
/ 10 июня 2011

Это хороший вопрос, потому что оптимальным решением ООП будет использование полиморфизма.В свой абстрактный класс Event добавьте абстрактный метод 'process', а затем в ваших подклассах реализуйте требуемую обработку.Тогда вы можете просто позвонить process() и не заботиться о том, какой это подкласс.

Однако вы, вероятно, хотите, чтобы ваши классы Event (то есть данные) были отделены от логики, чтобы где-то вы быливероятно, в конечном итоге вы будете делать instanceof или что-то вроде вашего перечисления.

У меня нет никаких предпочтений: возможно, один из них быстрее другого, и я, вероятно, предпочел бы использовать enum, а не instanceof, для скорости (очень хотелось бы услышать, если кто-то понимает это).

Если вы используете enum В вашем примере с событиями вы должны использовать переключатель вместо if..else.

2 голосов
/ 10 июня 2011

Наиболее подходящим ООП-подходом будет использование шаблона посетителя.

Поместите логику обработки отображения в Visitor:

public VisitorImpl implements Visitor {
    public void handleOutdoorEvent(OutdoorEvent event) { .. }
    public void handleOtherKindOfEvent(OtherKindOfEvent event) { .. }
}

И затем на каждом подклассе есть:

public void handleDisplay(Visitor visitor) {
     visitor.visit(this);
}

Тогда вместо нескольких проверок if вы просто делаете:

Visitor visitor = new VisitorImpl(..);
for (..) {
   entity.visit(visitor);
}

Кроме того, instanceof выглядит чище.

2 голосов
/ 10 июня 2011

Если вы имеете дело с Hibernate, то вам следует подготовиться к случаям с Hibernate Proxies (см., Например, Преобразование Hibernate Proxies в подклассы ): в вашем примере переменная , событие может быть создано динамическиэкземпляр HibernateProxy, и event instanceof OtherKindOfEvent не будет работать в этом случае.

Так что вам нужно либо отменить прокси (используя утилиты Hibernate и потерять JPA-абстракцию), либо использовать подход, который вы упомянули.Поэтому мое личное предпочтение - это второй вариант (или что-то подобное).

0 голосов
/ 10 июня 2011

Простой шаблон стратегии:

Map<Class<?>,Handler> handlers = new ArrayList();
handlers.add(SomeClass1.class, new Handler1());
handlers.add(SomeClass2.class, new Handler2());
handlers.add(SomeClass3.class, new Handler3());

....


for(Entity e : entities){
   handlers.get(e.getClass()).execute(e);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...