众所周知,我们dao层的操作就是为了完成数据库操作,但是针对不同的对象完成查询的代码往往只是因为操作对象的不同而需要我们重新大量的crud代码。这就造成了大量的代码重复。如何来解决这个问题呢?
如果我们能够将crud的代码抽取出来作为一个模板来用那就好了。然而我们的对象是不同的,因此我们是不是能把对象作为一个参数传入呢?
首先先分析我们的程序设计模型,一个domain对象就会对应一个crud的实现类,一个实现类对应一个接口,因此我们会得到和domain对象个数相同的接口数,将这些接口中的方法进行抽取得到一个基础接口,我们称之为baseDao :
public interface BaseDao<T>{
void save(T entity);
void delete(Long id);
void update(T entity);
T getByid(Long id);
List<T> findAll();
}
通过传入一个泛型,来代替我们的操作对象。
通过这个接口我们可以看出,我们将共有的方法抽取了出来,在下级接口(也就是与domain类对应的接口)中定义这个对象独有的方法(比如模糊查询,按照对象独有的特征进行查询等)
这样写也存在一个问题,就是方法实现的问题,为了降低代码的耦合度我们一般会给base接口配备一个实现类,让这个类来实现我们的方法。需要注意的是我们的这个base实现类也需要传入一个(T)对象,后续由分接口继承时只需要传入对应的对象即可。
public class BaseDaoImp<T> implements BaseDao<T> {}
public class MEmployeeImp extends BaseDaoImp<Employee> implements MEmployee {}
为整合hibernate做准备
封装私有的sessionFactory 并对 通过spring注入
public class BaseDaoImp<T> implements BaseDao<T> {
@Resource
private SessionFactory sessionFactory;
private Class<T> clazz=null;
//定义获取session的方法让子类继承时可以直接使用。
protected Session getSession(){
return sessionFactory.getCurrentSession();
}
@Override
public void save(T entity) {
getSession().save(entity);
}
@Override
public void delete(Long id) {
Object obj=getByid(id);
if(obj!=null)
getSession().delete(obj);
}
@Override
public void update(T entity) {
getSession().update(entity);
}
@Override
public T getByid(Long id) {
return (T)getSession().get(clazz, id);
}
@Override
public List<T> findAll() {
return getSession().createQuery("from "+clazz.getSimpleName()).list();
}
}
需要解决的问题:如何确定具体的modeal类型
// 使用反射机制来完成对象指定
public BaseDaoImp() {
/*通过在构造方法中获取对象,this.getClass()利用多态机制,获取实际的dao类,即我们在操作时new出的
类MEmployee mEmployee=new MEmployeeImp();也就是MEmployeeImp()
然后通过getGenericSuperclass()方法获取的是父类(它的父类是basedaoimp)的泛型。
然后再通过getActualTypeArguments()方法获取真实类型的对象,返回的是一个数组
因为我们的泛型可能是单个的也可能是map的成对的,因此要用数组来装下。
*/
ParameterizedType parameterizedType = (ParameterizedType) this
.getClass().getGenericSuperclass();
this.clazz= (Class<T>)parameterizedType.getActualTypeArguments()[0];
syso(clazz)//通过输出进行测试 没有问题的话会获取我们的实际对象,这样就完成了我们程序的抽取。
}