在Hibernate中,我们来浅谈一下泛型DAO
背景:最近项目组同事希望大家一起写一个泛型DAO,然后大家可以一起使用。
作为项目组中拥有审核代码权限的人,我认为,至少在使用Hibernate这个对象关系映射框架中,是不必要的。而我之所以反对的原因是
-
业务模型是复杂多变的,我们很难从其中抽取出共同的抽象类(有的业务模型十分复杂,有的业务模型简单,这些情况将会导致对于业务简单DAO层类需要继承很多不必要的方法)。
-
Hibernate对于对象关系映射已经封装的很好,没必要再写一个类似Hibernate关系对象映射的封装了。
-
抽象出来的DAO类很难复用,将会导致各个模块有着相同的业务逻辑。(举例来说,成员A写了一个用户模块(该用户模块只处理自己的业务逻辑:如用户权限控制,用户状态),成员B在完成订单模块的同时,需要用户模块的时候,是可以调用用户模块A,但是会面临着成员A会对用户模块进行重写的风险,往往为了规避这种风险存在,成员B就会对这个用户模块进行再次复写。这种大量重复的开发的确存在着)。
也正是因为以上的观点,我想出了一种基于抽象工厂、适配器的混合设计模式 。
Talk is cheap,show me the code
// DAO的工厂接口
public interface DaoFactory<T,P> {
// 取消注册
public void unrgistered(T type);
// 注册
public void register(T type,P provider);
// 更新
public void update(T type, P provider);
// 获取
public P valueOf(T type);
}
// DAO的适配器
@FunctionalInterface
public interface DaoProvider<T> {
public T of();
}
// DAO的类型
public interface DaoType {}
// DAO的抽象工厂
public abstract class AbstractDaoFactory<T extends DaoType,P extends DaoProvider<?>> implements DaoFactory<T,P>{
protected static final Map<DaoType, DaoProvider<?>> map = new ConcurrentHashMap<>(4);
@Override
public void register(T type,P provider){
Objects.requireNonNull(type);
Objects.requireNonNull(provider);
if (map.containsKey(type))
throw new DaoRegisteredException();
map.putIfAbsent(type, provider);
}
@Override
public void unrgistered(T type){
Objects.requireNonNull(type);
if (!map.containsKey(type))
throw new DaoUnregisteredException();
map.remove(type);
}
@Override
public void update(T type, P provider){
Objects.requireNonNull(type);
Objects.requireNonNull(provider);
if (!map.containsKey(type))
throw new DaoUpdatedException();
map.replace(type, provider);
}
@SuppressWarnings("unchecked")
@Override
public P valueOf(T type){
Objects.requireNonNull(type);
if (!map.containsKey(type))
throw new DaoUnregisteredException();
return (P) map.get(type);
}
}
public class DaoRegisteredException extends RuntimeException {
private static final long serialVersionUID = -3794217705148674984L;
public DaoRegisteredException() {
super("Dao has registered,using update method please...");
}
public DaoRegisteredException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public DaoRegisteredException(String message, Throwable cause) {
super(message, cause);
}
public DaoRegisteredException(String message) {
super(message);
}
public DaoRegisteredException(Throwable cause) {
super(cause);
}
}
public class DaoUnregisteredException extends RuntimeException {
private static final long serialVersionUID = 5997668949853885283L;
public DaoUnregisteredException() {
super("Dao still unregistered,using register method please...");
}
public DaoUnregisteredException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public DaoUnregisteredException(String message, Throwable cause) {
super(message, cause);
}
public DaoUnregisteredException(String message) {
super(message);
}
public DaoUnregisteredException(Throwable cause) {
super(cause);
}
}
public class DaoUpdatedException extends RuntimeException {
private static final long serialVersionUID = -1424730522134154582L;
public DaoUpdatedException() {
super("Dao still unregisted,using register method please...");
}
public DaoUpdatedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public DaoUpdatedException(String message, Throwable cause) {
super(message, cause);
}
public DaoUpdatedException(String message) {
super(message);
}
public DaoUpdatedException(Throwable cause) {
super(cause);
}
}
这里,我提供了DaoFactory的接口(注册,取消注册,更新Dao适配器与获取适配器等方法),并且同时提供了DAO的适配器、DAO的类型。
同时在AbstractDaoFactory中,我对其进行了简单的实现。到了这里,其实大家可以看出,我就是对于一个抽象模型的增删查改的DAO进行拆分。因为我现在设计的这些类要解决的就是上面的三个问题。
-
任何一个业务模型CURD必须细分出来,不需要继承不必要的抽象类,必须注册到DaoFactory中去。
-
不需要你去写适应项目组成员的泛型Dao。
-
你所实现的方法是可以给别人调用,因为当你需要进行重构你的代码的时候,你只能新增方法,不能修改你原先的业务逻辑。其他成员将会将会根据你的DaoType进行索引你的方法。
简单应用案例:
@SuppressWarnings("rawtypes")
public interface HotelOrderDetailDaoProvider extends DaoProvider<HotelOrderDetailQueryDao>{}
@FunctionalInterface
public interface HotelOrderDetailQueryDao<T> {
public T queryHotelOrderDetail(int id);
}
public final class HotelOrderDetailDaoFactory extends AbstractDaoFactory<HotelOrderDetailType,HotelOrderDetailDaoProvider> implements DaoFactory<HotelOrderDetailType,HotelOrderDetailDaoProvider>{
private static final Logger log=LoggerFactory.getLogger(HotelOrderDetailDaoFactory.class);
private static final HotelOrderDetailDaoFactory factory=new HotelOrderDetailDaoFactory();
private HotelOrderDetailDaoFactory(){
log.info("HotelOrderDaoFactory start accepting registration...");
}
/**
* @return
*/
public static HotelOrderDetailDaoFactory getInstance() {
return factory;
}
}
Thanks for reading,have a good night :)