zoukankan      html  css  js  c++  java
  • Abstract Factory

    解决什么问题

      考虑以下现实场景:数据库多种多样,我们可能从Mysql迁移到Oracle,甚至可能从关系型数据库迁移到非关系型数据库。我们不希望业务逻辑依赖具体的数据库实现,否则迁移数据库的时候,我们必须修改核心业务逻辑。怎么解决这个问题呢?依赖倒置,即核心业务逻辑定义数据持久化借口,即DAO接口。我们只要针对每种数据库,写一个DAO实现即可。

      

      那么,我们怎么生成DAO的对象呢?new一个具体的实现类是不合适的,因为这就把代码写死了,下次要换实现,还是得改核心业务逻辑的代码。这里我们需要一个工厂类,它有一个返回DAO对象的方法。我们来考察一下这个工厂类:

    1. 它一定是被核心逻辑所依赖的;
    2. 如果它是一个抽象类或一个接口,那么它的实现应该和DAO的实现在一个包里,有相同的提供方;
    3. 如果它是一个具体类,那么它只能通过classLoader来装载具体的DAO实现。因为DAO的实现依赖核心逻辑,而核心逻辑依赖工厂类,因此工厂类一定不能依赖DAO的实现,否则就循环依赖了;

      好了。问题到这里讨论结束。上面的2,实际上就是Abstract Factory,它解决的问题,实际上是多态的类(DAO)对象的创建,让多态类(DAO) 的使用方(核心业务逻辑),不必依赖于具体的类实现(Mysql DAO, Oracle DAO, ...),从而和具体的实现解耦。

    代码(Java)

    核心业务逻辑

     1 package com.mycompany.business;
     2 
     3 public class Business {
     4 
     5     /**
     6      * 之所以参数不是IDAO,而是factory,是因为factory是产生一组紧密相关对象的工厂
     7      * 假设这里除了IDAO之外,还有I1XXX, I2XXX,它们是一组相关的接口,它们都由工厂生产
     8      * 如果要把IDAO做参数,则I1XXX, I2XXX也得做参数
     9      * 随着相关的接口越来越多,参数也越来越多,这是不合适的。
    10      * @param daoFactory
    11      */
    12     public void process(DAOFactory daoFactory){
    13         BusinessEntity businessEntity = new BusinessEntity();
    14         businessEntity.setId(1L);
    15         IDAO dao = daoFactory.generateDAO();
    16         dao.insert(businessEntity);
    17         dao.delete(businessEntity.getId());
    18     }
    19 }
    1 package com.mycompany.business;
    2 
    3 public interface DAOFactory {
    4     IDAO generateDAO();
    5 }
    1 package com.mycompany.business;
    2 
    3 public interface IDAO {
    4     int insert(BusinessEntity businessEntity);
    5     int delete(Long id);
    6 }

    基础设施

    mysql实现

     1 package com.mycompany.infrastructure.mysql;
     2 
     3 import com.mycompany.business.DAOFactory;
     4 import com.mycompany.business.IDAO;
     5 
     6 public class MysqlDAOFactory implements DAOFactory {
     7     public IDAO generateDAO() {
     8         return new MysqlDAOImpl();
     9     }
    10 }
     1 package com.mycompany.infrastructure.mysql;
     2 
     3 import com.mycompany.business.BusinessEntity;
     4 import com.mycompany.business.IDAO;
     5 
     6 public class MysqlDAOImpl implements IDAO {
     7     public int insert(BusinessEntity businessEntity) {
     8         System.out.println("MysqlDAOImpl insert ...");
     9         return 0;
    10     }
    11 
    12     public int delete(Long id) {
    13         System.out.println("MysqlDAOImpl delete ...");
    14         return 0;
    15     }
    16 }

    oracle实现

     1 package com.mycompany.infrastructure.oracle;
     2 
     3 import com.mycompany.business.DAOFactory;
     4 import com.mycompany.business.IDAO;
     5 
     6 public class OracleDAOFactory implements DAOFactory {
     7     public IDAO generateDAO() {
     8         return new OracleDAOImpl();
     9     }
    10 }
     1 package com.mycompany.infrastructure.oracle;
     2 
     3 import com.mycompany.business.BusinessEntity;
     4 import com.mycompany.business.IDAO;
     5 
     6 public class OracleDAOImpl implements IDAO {
     7     public int insert(BusinessEntity businessEntity) {
     8         System.out.println("OracleDAOImpl insert ...");
     9         return 0;
    10     }
    11 
    12     public int delete(Long id) {
    13         System.out.println("OracleDAOImpl delete ...");
    14         return 0;
    15     }
    16 }

    进一步思考

    回到对工厂类的考察,那么3是什么呢?按我的理解,3就是经典的IoC,即控制反转。

    一个DAO,用不着我们自己new,而是由一个工厂产生,并且这个工厂不依赖具体的DAO实现,因此它只能通过classLoader来装载这个类。

     1 package com.mycompany.business;
     2 
     3 public class DAOFactory2 {
     4     public IDAO generateDAO(String className)  {
     5         try{
     6             Class<?> daoClass = Thread.currentThread().getContextClassLoader().loadClass(className);
     7             return (IDAO) daoClass.newInstance();
     8         }catch (Exception e){
     9             throw new RuntimeException("generateDAO error", e);
    10         }
    11 
    12     }
    13 }
  • 相关阅读:
    PHP的轻量消息队列php-resque使用说明
    Laravel 5.1 事件、事件监听的简单应用
    Ubuntu常用命令
    Mysql 主从数据库
    MySQL日志
    两条比较实用的mysql导入导出命令
    Linux下mysql定时自动备份并FTP到远程脚本
    观察者模式范例
    devexpress gridControl1导出为pdf文件时出现 中文乱码的解决方案
    devexpress打印gridControl
  • 原文地址:https://www.cnblogs.com/johnsblog/p/10358019.html
Copyright © 2011-2022 走看看