К сожалению, я чувствую, что основной поток разработчиков все еще боится этого.
Однако, по аналогии с пауками Хагрида, я бы сказал, что Дженерики — серьезно недооцененные существа… 🙂
Я надеюсь, что следующий пример продемонстрирует, насколько они могут быть полезны.
Проблема — классы 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 Order public void save(Order order){....} //getAll method return Orders List public List<Order> getAll(){...} } class UserDAO{ //save method receive an User public void save(User user){....} //getAll method return Users List public 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 Гал Левински в блоге Гал Левински .