抽象工厂模式
定义
提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类。
UML图
简单工厂、工厂和抽象工厂区别
用例
User类:用户类
public class User {
private Integer id;
}
IUser接口:用于客户端访问,解除与具体数据库i访问的耦合。
interface IUser{
void insert(User user);
User getUser(int id);
}
SqlserverUser类:访问SQL Server的User
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;
}
}
Access User:访问Access的User
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;
}
}
Department类:部门类
public class Department{
private Integer id;
}
IDepartment接口:用于客户端访问,解除与具体数据库访问的耦合
public interface IDepartment{
void insert(Department department);
Department getDepartment(int id);
}
SqlServerDepartment类:用于访问SqlServer的Department。
public class SqlServerDepartment implements IDepartment{
@Override
public void insert(Department department){
System.out.println("在SQL Server中给Department表增加一条记录");
}
@Override
public void getDepartment(int id){
System.out.println("在SQL Server中根据ID得到Department表一条记录");
}
}
Access Department :访问Access的Department
public class AccessDepartment implements IDepartment{
@Override
public void insert(Department department){
System.out.println("在Access中给Department表增加一条记录");
}
@Override
public User getDepartment(int id){
System.out.println("在Access中根据ID得到Department表一条记录");
return null;
}
}
IFactory接口:定义一个创建访问User表对象的抽象的工厂接口
public interface IFactory{
IUser createUser();
IDepartment createDepartment();
}
SqlServerFactory类:实现IFactory接口,实例化SqlServerUser和SqlServerDepartment。
public class SqlServerFactory implements IFactory{
@Override
public IUser createUser(){
return new SqlServerUser();
}
@Override
public IDepartment createDepartment(){
return new SqlServerDepartment();
}
}
AccessFactory类:实现IFactory接口,实例化AccessUser和AccessDepartment。
public class AccessFactory implements IFactory{
@Override
public IUser createUser(){
return new AccessUser();
}
@Override
public IDepartment createDepartment(){
return new AccessDepartment();
}
}
客户端代码
public static void main(String[] args){
User user = new User();
Department dept = 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(dept);
id.getDepartment(1);
}
优点
- 易于交换产品系列,由具体工厂类,例如IFactory factory = new SqlServerFactory(),在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,他只需要改变具体工厂即可使用不同的配置。
- 它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品具体类名也被具体工厂的实现分离,不会出现在客户端代码中。就像刚才的例子,客户端所认识的只有IUser和IDepartment,至于使用SQL server实现还是Access实现就不知道了。
缺点
比如要增加一个Department表就要增加很多类,IDepartment,SqlServerDepartment,MySqlDepartment,还需要更改IFactory、SqlServerFactory和MySqlFactory才可以完全实现。而且我们的客户端程序不止一个,很多地方都会用到IUser和IDepartment,如果100个地方要切换数据库就要改动100处代码。
用简单工厂来改进抽象工厂
去除IFactory、SqlServerFactory和MySqlFactory三个工厂类,用一个简单工厂DataAccess类实现:
public class DataAccess{
private final static String db = "SqlServer";//选择数据库
// private final static String db = "Access";
public static IUser createUser(){
IUser result = null;
switch (db){
case "SqlServer":
result = new SqlServerUser();
break;
case "Access":
result = new AccessUser();
break;
default:
break;
}
return result;
}
public static IDepartment createDepartment(){
IDepartment result = null;
switch (db){
case "SqlServer":
result = new SqlServerDepartment();
break;
case "Access":
result = new AccessDepartment();
break;
default:
break;
}
return result;
}
}
客户端代码:没有出现一个SqlServer或者Mysql的字样,实现了完全解耦。
public static void main(String[] args) {
User user = new User();
Department dept = new Department();
IUser iu = DataAccess.createUser();//此时已经和具体的数据库解除了依赖
iu.insert(user);
iu.getUser(1);
IDepartment id = factory.createDepartment();
id.insert(dept);
id.getDepartment(1);
}
UML图
缺点
比如增加一个Oracle数据库访问,本来抽象工厂增加一个OracleFactory工厂类就可以了,现在就比较麻烦了,需要在DataAccess类的每个switch语句中加case。