К сожалению, я чувствую, что основной поток разработчиков все еще боится этого.
Однако, по аналогии с пауками Хагрида, я бы сказал, что Дженерики — серьезно недооцененные существа… 🙂
Я надеюсь, что следующий пример продемонстрирует, насколько они могут быть полезны.
Проблема — классы DAO (объекты доступа к данным) имеют общие методы, такие как save, update, delete, loadAll .., которые требуются в каждом классе DAO.
Написание базового класса с помощью этих общих методов и расширение каждого объекта DAO просто недостаточно, поскольку каждый класс DAO представляет отдельный класс домена и, следовательно, тип, используемый в сигнатуре общих методов, различен (хотя реализация аналогична), пример:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
class OrderDAO {//save method receive an Orderpublic void save(Order order){....}//getAll method return Orders Listpublic List<Order> getAll(){...} }class UserDAO{//save method receive an Userpublic void save(User user){....}//getAll method return Users Listpublic List<User> getAll(){...}} |
Как Generics может помочь нам создать базовый класс с общей реализацией и, тем не менее, сохранить безопасность сигнатуры метода?
Во-первых, нам нужно определить интерфейс с помощью общих методов:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/** * Base interface for CRUD operations and common queries */public interface IDaoBase<T> { public List<T> loadAll(); public void save(T domain); public void update(T domain); public void delete(T domain); public T get(Serializable id); /** * Get list by criteria * @param detachedCriteria the domain query criteria, include condition and the orders. * @return * */ public List<T> getListByCriteria(DetachedCriteria detachedCriteria); public List<T> getListByCriteria(DetachedCriteria detachedCriteria, int offset, int size); } |
Обратите внимание, что мы используем дженерики, поэтому каждая сигнатура метода имеет тип T, который в реализованных классах DAO будет конкретным типом для каждого домена.
Второй шаг — создать абстрактный класс, который реализует общую функциональность:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
public abstract class DaoBase<T> extends HibernateDaoSupport implements IDaoBase<T> { private Class<T> entityClass; @Autowired public void setSession(SessionFactory sessionFactory){ this.setSessionFactory(sessionFactory); } public DaoBase() { entityClass = (Class<T>) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[0]; } public List<T> loadAll(){ return getHibernateTemplate().loadAll(entityClass); } public void delete(T domain) { getHibernateTemplate().delete(domain); } public void save(T domain) { getHibernateTemplate().saveOrUpdate(domain); } public void update(T domain) { getHibernateTemplate().merge(domain); } public T get(Serializable id) { T o = (T) getHibernateTemplate().get(entityClass, id); return o; } public List<T> getListByCriteria(DetachedCriteria detachedCriteria, int offset, int size) { return getHibernateTemplate().findByCriteria(detachedCriteria, offset, size); } public List<T> getListByCriteria(DetachedCriteria detachedCriteria) { return getHibernateTemplate().findByCriteria(detachedCriteria); }} |
Вот и все !
Потратьте минуту или две, чтобы проверить, как базовый объект реализует универсальную функциональность с учетом безопасности типов.
Все, что нам нужно сделать при внедрении нового DAO:
1. Интерфейс для расширения IDaoBase с конкретным типом
|
1
2
3
4
5
|
public interface DaoUser extends IDaoBase<User> {//<=Notice the User typing //Add any additional custom methods.. public User getbyUsername(String username); public User getbyEmail(String email);} |
2. Реализация для расширения DaoBase с конкретным типом
|
1
2
3
4
5
6
7
|
//This class has all the common methods, which are type safe for the User class@Repository("daoUser")public class DaoUserImpl extends DaoBase<User> implements DaoUser { //<=Notice the User typing public User getbyUsername(String username) {// concrete implmentation ... } |
Итак, теперь вы видите, насколько мощно использовать дженерики. Надеюсь, теперь это немного менее страшно и более понятно …
Ссылка: DAO layer — Обобщение для спасения от нашего партнера JCG Гал Левински в блоге Гал Левински .