Hibernate, подклассы и шаблон посетителя

Возможно, я использовал неправильное слово, поэтому, когда я говорю Business Object (BO), я имею в виду класс со ссылкой на класс, который отображается в таблицу базы данных с помощью Hibernate, а также бизнес-логику.

Проблема, с которой я сталкиваюсь, заключается в создании правильного BO для подклассов без использования отражения или instanceof.

Например, представьте, что у меня есть таблица Pen с одной ссылкой на таблицу Animal, в которой, в свою очередь, есть две вложенные таблицы Cat и Dog (все ссылки один на один). Классы выглядят примерно так:

public class Pen {
    private Animal a;
    // Getters and setters
}
public class Animal {
    // Getters and setters
}
public class Dog extends Animal {
    // Getters and setters
}
public class Cat extends Animal {
    // Getters and setters
}
public class PenBO {
    private Pen p;
    public AnimalBO getAnimalBO() { ... }
}
public interface Action {
    void visit(DogBO dbo);
    void visit(CatBO cbo);
}
public class Sound implements Action {
    void visit(DogBO dbo) { ... }
    void visit(CatBO cbo) { ... }
}
public interface AnimalBO {
    void accept(Sound s);
}
public class DogBO implements AnimalBO {
    Dog d;
    void accept(Sound s) {
        s.visit(this);
    }
}
public class CatBO implements AnimalBO {
    Cat c;
    void accept(Sound s) {
        s.visit(this);
    }
}

Затем я просто работаю с BO, создавая их таким образом в методах get этих BO:

Pen p = ... // Get or load from database 
PenBO pbo = new PenBO();
pbo.setPen(p);

Затем я использую такие классы:

pbo.getAnimalBO().accept(new Sound());

Это метод getAnimalBO, над которым я работаю. Я хочу, чтобы он возвращал правильный экземпляр BO, основанный на Animal-экземпляре Pen.

Я "мог" использовать instanceof для проверки фактического Animal из текущего пера, но это явно не красиво. Другой альтернативой, о которой я думал, было использование отражения, чтобы получить имя класса и потом добавить "BO" и получить экземпляр этого, однако это также довольно уродливо.

Я попытался обернуть другой шаблон посетителя вокруг getAnimalBO, но он не может выбрать правильный метод посещения без приведения, и я не хочу добавлять accept-методы к классам не-BO.

Если нет никакого умного способа заставить этот метод работать эффективно, что-то не так в ядре? Я действительно не нашел лучших практик для Hibernate. Некоторые примеры Hibernate и шаблона посетителя просто добавляют методы accept к сопоставленным классам, что не может быть хорошим...

1 ответ

Решение

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

В настоящее время часть вашего кода будет нести ответственность за знание того, что CatBO соответствует Cat и т. д., а также для того, чтобы знать, что если Pen объекты Animal собственность на самом деле Cat, то содержащий PenBO объекты AnimalBO собственность на самом деле будет CatBO, Учитывая это, он должен быть в состоянии определить тип Animal экземпляр возвращен, поэтому я не вижу, как можно избежать использования одного из instanceof или отражение. Что вы возражаете против instanceof? Отражение, чтобы получить имя класса и добавление "BO", очень противно и некрасиво, я согласен, хотя это, очевидно, может быть сделано для работы. Но единственный метод, ответственность которого состоит в том, чтобы взять Animal и вернуть подходящий AnimalBO используя instanceof и выбрав правильный BO класс не плохая вещь в данных обстоятельствах ИМХО.

Вопрос, который я хотел бы задать, заключается в том, почему вы вообще так отображаете иерархию классов. Вы сказали, что не хотите добавлять accept методы к отображенным классам, и что это "не может быть хорошо", но вы еще не объяснили, почему вы так чувствуете. Это хуже, чем варианты, которые вы уже представили? Добавляя шаблон посетителя в сопоставленную иерархию классов, вы на самом деле не внедряете в него какую-либо бизнес-логику, вы просто разрешаете применение бизнес-логики по всей иерархии с использованием шаблона посетителя. Таким образом, ваш уровень бизнес-логики содержит простые, общие реализации посетителя, ваш сопоставленный класс или уровень домена - это POJO плюс базовая реализация посетителя, и у вас действительно есть хорошее чистое разделение, которое, я думаю, вам нужно.

Другие вопросы по тегам