(二十四)设计模式-抽象工厂模式

本文深入解析抽象工厂模式,探讨其在数据库访问层的应用,通过示例展示如何在不同数据库间切换,保持代码的高灵活性与扩展性。同时,对比简单工厂模式,分析各自的优劣。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、定义

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

2、使用场景

一个项目,早期使用的数据是Sql Server,但是现在需要切换数据Access,甚至到了后期可能需要换成Oracle,相应的对应的查询插入删除等方法需要做出调整。需要找出最佳解决办法适应各种数据库,且改动较小,易于扩展,耦合性底。

3、代码结构UML图

在这里插入图片描述

4、类的实现

(1)、User、Department(实体类)
public class User {
    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class Department {
    private String id;
    private String name;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}
(2)IUser、IDepart(接口用于客户端访问,解除与具体数据库访问的耦合)
public interface IUser {
    void insert(User user);
    User getUser(int id);
}
public interface IDepartment {
    void  insert(Department department);
    Department getDepartment(int id);
}
(3)、IFactory(抽象工厂类)
public interface IFactory {
    IUser createUser();
    IDepartment createDepartment();
}
(4)、SqlServerFactory 、AccessFactory (具体工厂类)
public class SqlServerFactory implements IFactory {
    @Override
    public IUser createUser() {
        return new SqlServerUser();
    }

    @Override
    public IDepartment createDepartment() {
        return new SqlServerDepartment();
    }
}
public class AccessFactory implements IFactory {
    @Override
    public IUser createUser() {
        return new AccessUser();
    }

    @Override
    public IDepartment createDepartment() {
        return new AccessDepartment();
    }
}
(5)SqlServerUser、SqlServerDepartment、AccessUser AccessDepartment(用于访问数据库的User、Department)
public class SqlServerUser implements IUser {
    @Override
    public void insert(User user) {
        System.out.println("在Sql Server 中给User表增加一条记录。");
    }

    @Override
    public User getUser(int id) {
        System.out.println("在Sql Server 中根据ID得到User表一条记录");
        return null;
    }
}
public class SqlServerDepartment implements IDepartment {
    @Override
    public void insert(Department department) {
        System.out.println("在Sql Server 中给Department表增加一条记录。");
    }

    @Override
    public Department getDepartment(int id) {
        System.out.println("在Sql Server中根据ID得到Department表一条记录。");
        return null;
    }
}
public class AccessUser implements IUser {
    @Override
    public void insert(User user) {
        System.out.println("在Access 中给User表增加一条记录。");
    }

    @Override
    public User getUser(int id) {
        System.out.println("在Access中根据ID得到User 表一条记录。");
        return null;
    }
}
public class AccessDepartment implements IDepartment {
    @Override
    public void insert(Department department) {
        System.out.println("在Access 中给Department表增加一条记录。");
    }

    @Override
    public Department getDepartment(int id) {
        System.out.println("在Access中根据ID得到Department表一条记录。");
        return null;
    }
}
(6)注意:简单工厂模式:需要简化抽象工厂,演变后:
public class DataAccess {
    private static String assemblyName = "factory.abstractFactory";//包名
    private static String db = "SqlServer";//数据库名称,可以替换成Access

    public static IUser createUser() {
        //根据包名和类名来创建实例,消除switch case 语句
        String className = assemblyName + "." + db + "User";
        try {
            return (IUser) Class.forName(className).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static IDepartment createDepartment() {
        //根据类名来创建实例,消除switch case 语句
        String className = assemblyName + "." + db + "Department";
        try {
            return (IDepartment) Class.forName(className).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}

5、客户端调用

(1)、抽象工厂模式调用
public static void main(String[] args) {
        User user = new User();
        Department department = new Department();

        IUser iu = DataAccess.createUser();
        iu.insert(user);
        iu.getUser(1);

        IDepartment id = DataAccess.createDepartment();
        id.insert(department);
        id.getDepartment(1);
    }
(2)、简单工厂模式调用
public static void main(String[] args) {
        User user = new User();
        Department department = new Department();

        //IFactory factory=new SqlServerFactory();

        IFactory factory = new AccessFactory();

        IUser iu = factory.createUser();
        iu.insert(user);
        iu.getUser(1);

        IDepartment id = factory.createDepartment();
        id.insert(department);
        id.getDepartment(1);
    }
输出:

在这里插入图片描述

6、总结

此模式相对来讲比较抽象一点,而且演化过程也非常有意思,大家可以参看书里面案例和演化过程。
抽象工厂模式:更多的是将工厂进行了抽象,对应的访问对象也进行了再次抽象,灵活性和扩展性是比较高的,比如例子中添加oracle数据库,只需要在创建一个OracleFactory类,然后创建对应的OracleUser、OracleDepartment三个类即可,对原来的SqlServer、Access数据库访问不会造成任何影响,耦合性低,易于扩展,但是缺点也是很明确的,就是类会变得比较多。当类变得比较多的时候可以考虑简单工厂模式,无需OracleFactory 这个类,只需要OracleUser、OracleDepartment这个两个类,改动DateAccess对应的包和类访问路径即可。


参考:《大话设计模式》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值