Статьи

Слой DAO — Дженерики на помощь

Обобщения могут быть мощным инструментом для создания многократно используемого кода с возможностью проверки во время компиляции (тип безопасности ..).

К сожалению, я чувствую, что основной поток разработчиков все еще боится этого.

Однако, по аналогии с пауками Хагрида, я бы сказал, что Дженерики — серьезно недооцененные существа… 🙂

Я надеюсь, что следующий пример продемонстрирует, насколько они могут быть полезны.

Проблема — классы 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 Гал Левински в блоге Гал Левински .