美文网首页
第15章 就不能不换DB吗?--抽象工厂模式

第15章 就不能不换DB吗?--抽象工厂模式

作者: 落墨Zero | 来源:发表于2018-07-11 14:51 被阅读0次

    情境:在需要更改项目数据库时,代码尽量少的更改。

    为了可以切换数据库,首先可以想到使用工厂方法模式,定义一个用于创建对象的接口,让子类决定实例化哪一个类。

    代码如下

    IUser接口,用于客户端访问,解除与具体数据库访问的耦合。

    public interface IUser {
    
        void insert(User user);
    
    }
    

    SqlServerUser类,用于访问SqlServer的User

    public class SqlServerUser implements IUser{
    
        @Override
        public void insert(User user){
            print("在SQL Server中给User表增加一条记录");
        }
    
    }
    

    AccessUser类,用于访问Access的User

    public class AccessUser implements IUser{
    
        @Override
        public void insert(User user){
            print("在Access中给User表增加一条记录");
        }
    
    }
    

    IFactory接口,定义一个创建访问User表对象的工厂接口

    public interface IFactory {
    
        IUser getUserFactory();
    
    }
    
    

    SqlServerFactory类,实现IFactory接口,实例化SqlServerUser

    public class SqlServerFactory implements IFactory {
        @Override
        public IUser createUserFactory() {
            return new SqlServerUser();
        }
    }
    

    AccessFactory类,实现IFactory接口,实例化AccessUser

    public class AccessFactory implements IFactory {
        @Override
        public IUser createUserFactory() {
            return new AccessUser();
        }
    }
    

    测试代码

    public class Test {
    
        public static void main(String[] args) {
            User user = new User();
            //若要改成Access数据库,只需要将本句改成IFactory factory = new AccessFactory();
            IFactory factory = new SqlServerFactory();
            IUser userFactory = factory.createUserFactory();
            userFactory.insert(user);
        }
    
    }
    

    此时,由于多态的关系,使得声明IUser接口的对象userFactory事先根本不知道是在访问哪个数据库,却可以在运行时很好地完成工作,这就是所谓的业务逻辑与数据访问的解耦。
    但是如果增加一个部门表(Department表),需要做下面的改动。

    新增IDepartment接口,用于客户端访问,解除与具体数据库访问的耦合

    public interface IDepartment {
    
        void insert(Department department);
    
    }
    

    新增SqlServerDepartment类,用于访问SqlServer的Department

    public class SqlServerDepartment implements IDepartment{
    
        @Override
        public void insert(Department department){
            print("在SQL Server中给Department表增加一条记录");
        }
    
    }
    

    新增AccessDepartment类,用于访问Access的Department

    public class AccessDepartment implements IDepartment{
    
        @Override
        public void insert(Department department){
            print("在Access中给Department表增加一条记录");
        }
    
    }
    

    修改IFactory接口

    public interface IFactory {
    
        IUser createUserFactory();
    
        IDepartment createDepartmentFactory();
    }
    

    修改SqlServerFactory

    public class SqlServerFactory implements IFactory {
        @Override
        public IUser createUserFactory() {
            return new SqlServerUser();
        }
    
        @Override
        public IDepartment createDepartmentFactory() {
            return new SqlServerDepartment();
        }
    }
    

    修改AccessFactory

    public class AccessFactory implements IFactory {
        @Override
        public IUser createUserFactory() {
            return new AccessUser();
        }
    
        @Override
        public IDepartment createDepartmentFactory() {
            return new AccessDepartment();
        }
    }
    

    抽象工厂模式

    抽象工厂模式(Abstract Factory),提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。[DP]

    抽象工厂模式(Abstract Factory)结构图

    抽象工厂模式结构图.png

    AbstractProductA和AbstractProductB是两个抽象产品,之所以为抽象,是因为它们都有可能有两种不同的实现,就刚才的例子来说就是User和Department,而ProductA1、ProductA2和ProductB1、ProductB2就是对两个抽象产品的具体分类的实现,比如ProductA1可以理解为是SqlServerUser,而ProductB1是AccessUser。
    IFactory是一个抽象工厂接口,它里面应该包含所有的产品创建的抽象方法。而ConcreteFactory1和ConcreteFactory2就是具体的工厂。就像SqlServerFactory和AccessFactory一样。
    通常是在运行时刻再创建一个ConcreteFactory类的实例,这个具体的工厂再创建具有特定实现的产品对象,也就是说,为创建不同的产品对象,客户端应使用不同的具体工厂。

    抽象工厂模式的优点与缺点

    优点

    1、易于交换产品系列,由于具体工厂类,在一个应用中只需要再初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。
    2、它让具体的创建实例过程与客户端分离,客户端是通过他们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。

    缺点

    每一个类的开始都要声明IFactory factory = new SqlServerFactory()新增功能,需要修改Factory相关类。

    用简单工厂来改进抽象工厂

    新增DataAccess类

    public class DataAccess {
    
        private static final String db = "SqlServer";
    
        public static IUser createUser() {
            IUser result = null;
            switch (db) {
                case "SqlServer":
                    result = new SqlServerUser();
                    break;
                case "Access":
                    result = new AccessUser();
                    break;
            }
            return result;
        }
    
        public static IDepartment createDepartment() {
            IDepartment result = null;
            switch (db) {
                case "SqlServer":
                    result = new SqlServerDepartment();
                    break;
                case "Access":
                    result = new AccessDepartment();
                    break;
            }
            return result;
        }
    }
    

    测试代码

    public class Test {
    
        public static void main(String[] args) {
            User user = new User();
            IUser userFactory = DataAccess.createUser();
            userFactory.insert(user);
        }
    
    }
    
    

    抛弃IFactory、SqlServerFactory、AccessFactory三个工厂类,取而代之的是DataAccess类,客户端没有出现任何一个SqlServer或Access的字样,达到解耦的目的。

    用反射解决switch case

    修改DataAccess类

    public class DataAccess {
    
        private static final String fullName = "com.luomo.study.design.patten.absfactory.";
    
        private static final String db = "Access";
    
        public static IUser createUser() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
            Class<?> cls = Class.forName(fullName+db+"User");
            return (IUser) cls.newInstance();
        }
    
        public static IDepartment createDepartment() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
            Class<?> cls = Class.forName(fullName+db+"Department");
            return (IDepartment) cls.newInstance();
        }
    }
    

    所有在用简单工厂的地方,都可以考虑用反射技术来去除switch或if,解除分支判断带来的耦合。

    相关文章

      网友评论

          本文标题:第15章 就不能不换DB吗?--抽象工厂模式

          本文链接:https://www.haomeiwen.com/subject/mmthpftx.html