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 }
  • 相关阅读:
    SVN服务器搭建(一)
    排序算法二:冒泡排序
    【LeetCode】136. Single Number
    【LeetCode】217. Contains Duplicate
    【LeetCode】189. Rotate Array
    【LeetCode】122. Best Time to Buy and Sell Stock II
    【LeetCode】26. Remove Duplicates from Sorted Array
    【LeetCode】20. Valid Parentheses
    【LeetCode】680. Valid Palindrome II
    【LeetCode】345. Reverse Vowels of a String
  • 原文地址:https://www.cnblogs.com/johnsblog/p/10358019.html
Copyright © 2011-2022 走看看