好好学习,天天向上!

DAO与Factory模式的结合——持久层的设计模式分析(深入浅出Hibernate笔记) .

解耦合的设计目标:
     1. 应用层解耦合--应用逻辑与数据逻辑相分离。
     2. 资源层解耦合--逻辑结构与物理结构相分离。

DAO模式:即Data Accessor模式和Active Domain Object模式。
     Data Accessor模式:实现数据访问和业务逻辑的分离。
     Active Domain Object:实现了业务数据的对象化封装。
     Domain Object:简单来讲就是对领域内涉及的各个数据对象,反映到代码,就是一个拥有相关属性的getter,setter方法的java Bean。
     DAO模式通过对业务逻辑层提供数据抽象层接口,实现了以下目标:
         1. 数据存储逻辑的分离:通过对数据访问逻辑进行抽象,为上层结构提供抽象化的数据访问接口。
         2. 数据访问底层实现的分离:数据访问划分为抽象层和实现层,从而分离了数据使用和数据访问的底层实现细节。
         3. 资源管理和调用的分离。
         4. 数据抽象:DAO模式通过对底层数据的封装,为业务层提供了一个面向对象的接口,使得业务逻辑开发人员可以面向业务中的实体进行编程。
         DAO = Data+Accessor+Domain Object

DAO模式的进一步改良
     Factory模式的引入:
        由于需要针对不同的数据库访问机制分别提供各个版本的Data Accessor实现,自然我们会想到通过java interface定义一个调用接口,然后针对这个调用接口实现不同数据库的Data Accessor。通过接口作为调用界面和实现规范,可以避免对具体实现的依赖。
Public interface CustomerDAO{   
     Public Customer getCustomer(String custID);   
     Puboic void save (Customer customer);   
}  

作为最常见的创建模式,Factory模式在这里起到连接接口和实现的桥梁作用,通过Factory模式,我们可以根据具体的需要加载相应的实现,并将此实现作为所对应接口的一个实例提供给业务层使用。
CustomerDAO custDAO =(CustomerDAO)DAOFactory.getDAO(CustomerDAO.class);   
Customer customer = custDAO.getCustomer(customerID);


业务逻辑层通过接口调用底层实现,具体的DAO实现类不会出现在我们的业务代码中。而具体实现类在配置文件中加以配置,之后DAOFactory.getDAO方法通过读取配置文件获得当前我们期望使用的实现类的类名,再通过java Class动态加载机制加载返回。
从而我们的代码不依赖于某个特定的实现类,只需要在部署的时候在配置文件中指定当前采用的实现类即可。
public class DAOFactory {   
     private static HashMap daoMap = null;
     //根据指定的Class来获取DAO实例
     public static Object getDAO(Class daoInterface){   
         initial();   
         Object dao = daoMap.get(daoInterface);   
         if(null ==dao){   
             throw new DAOException("No Implementation found of DAO interface =>"  
                     +daoInterface.getName());   
         }   
         return dao;   
     }   
    //初始化DAOFactory,加载DAO interface和
    //implementation到daoMap中
     public static synchronized void initial(){   
         if(null==daoMap){   
             daoMap =DAOConfig.load();//根据配置文件加载DAO实现配置   
         }   
     }   
}  
//DAOConfig类实现了配置文件的读取功能,并根据配文件中的内容加载指定的接口和实现
public class DAOConfig {   
     private static Logger logger = LogManager.getLogger(DAOConfig.class);   
     private static final String DAO_CONFIG_FILE="dao.xml";   
     private static final String DAO_CONFIG_SECTION="DAO";   
     public static synchronized HashMap load(){   
         HashMap map = new HashMap();   
         JFigLocator jfigLocator = new JFigLocator(DAO_CONFIG_FILE);   
         JFigIF daoConfig = JFig.getInstance(jfigLocator);   
         Properties prop = daoConfig.getSectionAsProperties(DAO_CONFIG_SECTION);   
         Enumeration enumSection = prop.keys();   
         while(enumSection.hasMoreElements()){   
             String daoIface =(String)enumSection.nextElement();   
             String daoImpl = prop.getProperty(daoIface);   
             try{   
                 Class iface = ClassToolKit.loadClass(daoIface);   
                 Class impl = ClassToolKit.loadClass(daoImpl);   
                 //将接口作为HashMap索引,实现类作为值   
                 map.put(iface, impl);   
             }catch(ClassNotFoundException e){   
                 logger.debug("No Class Found"+e);   
             }   
         }//while enumSection   
         return map;   
     }   
}

ClassToolKit.loadClass方法实现了类文件的动态加载:
public class ClassToolKit {   
     public static Class loadClass(String className)   
                 throws ClassNotFoundException{   
         Class cls = null;   
         try{   
             //首先尝试用当前ClassLoader加载   
             cls = Thread.currentThread().getContextClassLoader().loadClass(className);   
         }catch(Exception e){   
             e.printStackTrace();   
         }   
         if(cls == null){   
             //如果通过当前ClassLoader加载失败,使用系统ClassLoader加载   
             cls = Class.forName(className);   
         }   
         return cls;   
     }   
}

这样,通过接口与实现的分离,并结合DAOFactory动态加载实现类,我们就实现了底层访问实现的参数化配置功能。从而为增强产品的部署能力提供了强有力的支持。
    经过Factory模式的改造,业务层代码进行相应的修改:
public class Customers {   
     public BigDecimal calcAmount(String customerID,BigDecimal amount){   
         //根据客户ID获得客户记录   
         CustomerDAO customerDAO = (CustomerDAO)DAOFactory.getDAO(CustomerDAO.class);
         Customer customer = customerDAO.getCustomer(customerID);   
         //根据客户等级获得打折比率   
         PromotionDAO promoDAO = (PromotionDAO)DAOFactory.getDAO(PromotionDAO.class);
         Promotion promotion = promoDAO.getPromotion(customer.getLevel());   
         //累计客户总消费,并更新数据库   
         customer.setSumAmount(customer.getSumAmount().add(amount));   
         customerDAO.save(customer);   
         //返回打折后金额   
         return amount.multiply(promotion.getRatio());   
     }
}
这段代码中混杂了数据访问层的内容,如DAOFactory.getDAO方法的调用。
posted @ 2012-12-12 16:32  忍性而为  阅读(624)  评论(1编辑  收藏  举报
好好学习,天天向上!