zoukankan      html  css  js  c++  java
  • 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方法的调用。
  • 相关阅读:
    javascript高级编程笔记03(正则表达式)
    javascript高级编程笔记02(基本概念)
    javascript高级编程笔记01(基本概念)
    ExtJS4加载FormPanel数据的几种方式
    Extjs 更新数据集Ext.PagingToolbar的start参数重置的处理
    四川绵阳 晴
    四川绵阳 阴
    四川绵阳 晴
    在IntelliJ IDEA中添加repository模板
    List分组 用于客服对话分组场景
  • 原文地址:https://www.cnblogs.com/a1280055207/p/2814892.html
Copyright © 2011-2022 走看看