Приветствую форумчан!
Имеется такая иерархия классов (модификаторы доступа и ненужные для общей картины элементы опущены):
| Код | /** абстрактный класс, представляющий содержимое файлообменника */ abstract class Content { // общие поля типа Name, Description, Size, etc } class Film extends Content { int year; // год выпуска фильма } class Software extends Content { String version; // номер версии софтины }
/** Категория, хранящая экземпляры подклассов класса Contеnt Один подкласс - одна категория */ class Category { List<Content> items; }
|
Наследование замаплено примерно так
Content.hbm.xml
| Код | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="ru.balza.filex.logic.content"> <class name="Content" abstract="true"> <id column="CONTENT_ID" name="id"> <generator class="native" /> </id> <discriminator column="DSK" type="string" length="30" not-null="true"/> <property name="name" type="string"/> <property name="description" type="string"/> <property name="size" type="int"/> <property name="URL" type="string"/> <many-to-one name="category" class="Category" column="CATEGORY_ID" not-null="true" lazy="false"/> <bag name="tags" cascade="save-update" table="tags_and_content" lazy="false"> <key column="CONTENT_ID"/> <many-to-many class="Tag" column="TAG_ID"/> </bag> <bag name="comments" cascade="save-update" lazy="false"> <key column="CONTENT_ID"/> <one-to-many class="Comment"/> </bag> </class> </hibernate-mapping>
|
Film.hbm.xml
| Код | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="ru.balza.filex.logic.content"> <subclass name="Film" extends="Content" discriminator-value="Film"> <property name="originalName" column="original_name" type="string"/> <property name="director" type="string"/> <property name="year" type="int"/> <property name="country" type="string"/> </subclass> </hibernate-mapping>
|
Экземпляр Content (точнее экземпляр любого из его субклассов) вне Категории существовать не может и не должен. Это связывает меня по рукам и ногам тем, что когда я хочу вытащить из базы экзмепляр Contenta (т.е. его субклассов), мне нужно явно указывать конкретный субкласс, к которому полученный объект нужно будет прикастить.
| Код | // где то в ContentDAO implementation public Content getContentById(int contentId) throws SQLException { ... session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); // 1. Content c = session.get(Content.class, contentId); // ошибка, Content - абстрактный класс // 2. Content c = session.get(Film.class, contentId); // корректно // 3. Content c = session.get(Software.class, contentId); // так тоже корректно ... return c; }
|
Получается что все время надо "таскать" за собой ссылку на этот нужный класс (Film или Software или любой другой подкласс Content). В данный момент у меня это реализовано в виде метода в классе Category, возвращающего ссылку на класс объектов, которые хранит данная категория :
| Код | class Category { List<Content> items; ...
static final int UNDEFINED_TYPE = 0; static final int FILMS_TYPE = 1; static final int SOFTWARE_TYPE = 2; static final Map<Integer, Class> typesMap; static { typesMap = new HashMap<Integer, Class>(); typesMap.put(UNDEFINED_TYPE, null); typesMap.put(FILMS_TYPE, Film.class); typesMap.put(SOFTWARE_TYPE, Software.class); } ...
/** тип категории, сигнализирует о том, объекты какого класса хранит категория */ private int type; ...
public Class getContentClass() { return typesMap.get(type); } }
|
инициализация категории:
| Код | Category cat = new Category(); cat.setType(Category.FILMS_TYPE); ...
|
Применение:
| Код | public class ContentDAOHibernateImpl implements ContentDAO {
... public Content getContentById(Category category, int contentId) throws SQLException { Session session = null; Content content = null; try { session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction();
Class contentClass = category.getContentClass(); // ссылка на класс if (contentClass != null) { content = (Content) session.get(contentClass, contentId); } } catch(Exception ex) { ex.printStackTrace(); } finally { if (session != null && session.isOpen()) { session.close(); } } return content; } ... }
|
Хотелось бы узнать насколько такой способ хорош (или вообще допустим)? Можно ли избавиться от повсеместного "таскания" Category? Какова Best Practice, так сказать... |