抽象工厂模式 模式引入 问题描述 数据库是应用中不可缺少的组件,假设我们的应用最开始时使用 MySQL,但是某一天突然需要接一个 Access,两个数据库在很多方面都不相同,原来的创建、更新、删除、查询相关代码都需要修改。最简单的方案是直接针对 Access 重新写一套,最外面用一个参数来判断是使用哪种库,并路由到对应的逻辑。 但是好景不长,又接到了一个 Oracle,这时候怎么办,再写一套新的,再多一个判断分支?当然也未尝不可。但这种情况已经出现两次了,聪明的你可能已经意识到了,万一过几天再来一个新的怎么办,干脆将业务逻辑和具体的库隔离开。 模式定义 当有多个产品或相关产品系列时,通过组合的方式将创建对象的任务委托给其他类,可以保证多个或系列产品的一致性。
数据库是应用中不可缺少的组件,假设我们的应用最开始时使用 MySQL,但是某一天突然需要接一个 Access,两个数据库在很多方面都不相同,原来的创建、更新、删除、查询相关代码都需要修改。最简单的方案是直接针对 Access 重新写一套,最外面用一个参数来判断是使用哪种库,并路由到对应的逻辑。
但是好景不长,又接到了一个 Oracle,这时候怎么办,再写一套新的,再多一个判断分支?当然也未尝不可。但这种情况已经出现两次了,聪明的你可能已经意识到了,万一过几天再来一个新的怎么办,干脆将业务逻辑和具体的库隔离开。
当有多个产品或相关产品系列时,通过组合的方式将创建对象的任务委托给其他类,可以保证多个或系列产品的一致性。也使得交换产品系列更加方便,一个具体工厂只在初始化时出现一次,只需修改这里就可以使用不同的产品配置。
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类。它是一般化的工厂方法,可以看做一组工厂方法的集合。
我们用抽象工厂模式重新设计开始时的问题。就是把增删改查的逻辑抽离出来,与实际的数据库解耦,我们通过新创建一个对应数据库(比如 MySQL)的工厂,该工厂新建、更新和删除的每张表都是与该数据库相对应的,它们都接受相同的业务参数。
我们以 User 表和 Department 两张表为例。
Factory 的接口类,定义 createProduct 方法:createUser 和 createDepartment。ConcreteFactory:SqlServerFactory 和 AccessFactory,然后通过重写上面的两个方法,使其可以创建对应数据库的不同表(产品)。Product 的接口类:Department 和 User,定义 insert 和对应的 getProduct 方法。ConcreteProduct,并重写自己的插入方法。下面是一些注意事项:
Factory 类:
public interface Factory { User createUser(); Department createDepartment(); }
ConcreteFactory 类:
public class SqlServerFactory implements Factory { @Override public User createUser() { return new SqlServerUser(); } @Override public Department createDepartment() { return new SqlserverDepartment(); } } public class AccessFactory implements Factory { @Override public User createUser() { return new AccessUser(); } @Override public Department createDepartment() { return new AccessDepartment(); } }
Product 类:
public interface User { void insert(User user); User getUser(int id); } public interface Department { void Insert(Department department); Department getDepartment(int id); }
ConcreteProduct 类:
public class SqlServerUser implements User { @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 AccessUser implements User { @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 SqlserverDepartment implements Department{ @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 AccessDepartment implements Department { @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; } }
Main 方法:
public class Main { public static void main(String[] args) { User user = new AccessUser(); Department dept = new AccessDepartment(); Factory factory = new AccessFactory(); User iu = factory.createUser(); iu.insert(user); iu.getUser(1); Department department = factory.createDepartment(); department.Insert(dept); department.getDepartment(1); } }
执行结果:
在Access中给User表增加一条记录 在Access中根据ID得到User表一条记录 在Access中给Department表增加一条记录 在Access中根据ID得到Department表一条记录

实际中的例子:极少扩展的产品系列。
抽象工厂模式优点包括:
抽象工厂模式缺点包括: