抽象工厂(AbstractFactory)模式,提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
抽象工厂模式与工厂方法模式的区别:
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
优点:
(1)分离了具体的类。客户通过抽象接口操纵实例,产品的类名也在具体工厂的实现中被分离,它们不出现在客户代码中。
(2)易于交换产品系列。一个具体工厂类只在初始化时出现一次,这使得改变一个应用的具体工厂变得很容易,只需改变具体的工厂即可使用不同的产品配置。
(3)有利于产品的一致性。当一个系列的产品对象被设计成一起工作时,一个应用一次只能使用同一个系列中的对象,这一点很重要,而抽象工厂很容易实现这一点。
缺点:
当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。
代码实现:
以数据访问程序为例
最基本的程序
创建用户类:
class User
{
private int _id;
private String _name;
public int get_id() {
return _id;
}
public void set_id(int _id) {
this._id = _id;
}
public String get_name() {
return _name;
}
public void set_name(String _name) {
this._name = _name;
}
}
创建SqlserverUser类——用于使用SQL server操作User表:
class SqlserverUser
{
//新增用户,
public void Insert(User user)
{
System.out.println(“在Sqlserver中给User表增加一条记录”);
}
//得到用户,
public User GetUser(int id)
{
System.out.println("在Sqlserver中根据ID得到User表一条记录");
return null;
}
}
客户端代码:
public static void Main(String[] args){
User user = new User();
SqlserverUser su = new SqlserverUser();//与SQL server耦合
su.Insert(user);//插入用户
su.GetUser(1);//得到ID为1的用户
}
这样无法选择其他数据库对User表进行操作,因为su这个对象被框死在SQL server上了,我们使用工厂方法模式对代码进行改进,增加Access类。
//IUser接口,用于客户端访问,解除与具体数据库的耦合,
interface IUser
{
void Insert(User user);
User GetUser(int id);
}
//SqlserverUser类,用于访问SQLServer的User,
class SqlserverUser implements IUser
{
//新增用户,
public void Insert(User user)
{
System.out.println(“在Sqlserver中给User表增加一条记录”);
}
//得到用户,
public User GetUser(int id)
{
System.out.println("在Sqlserver中根据ID得到User表一条记录");
return null;
}
}
//AccessUser类,用于访问Access的User
class AccessUser implements IUser
{
public void Insert(User user)
{
System.out.println(“在Access中给User表增加一条记录”);
}
public User GetUser(int id)
{
System.out.println("在Access中根据ID得到User表一条记录");
return null;
}
}
//IFactory接口,定义一个创建访问User表对象的抽象的工厂接口,
interface IFactory
{
IUser CreateUser();
}
//SqlServerFactory类,实现IFactory接口,实例化SqlserverUser,
class SqlServerFactory implements IFactory
{
public IUser CreateUser()
{
return new SqlserverUser();
}
}
//AccessFactory类,实现IFactory接口,实例化AccessUser,
class AccessFactory implements IFactory
{
public IUser CreateUser()
{
return new AccessUser();
}
}
客户端代码:
User user = new User();
IFactory factory = new SqlserverFactory();//若要改成Access数据库,只需将本句改成IFactory factory = new AccessFactory();
IUser iu = factory.CreateUser();
iu.Insert(user);
iu.GetUser(1);
现在要更换数据库,只需将new SqlserverFactory()改成new AccessFactory(),此时由于多态关系,使得声明IUser接口的对象iu事先根本不知道是在访问哪个数据库,却可在运行时很好的完成工作,这就是所谓的业务逻辑与数据访问的解耦。
数据库中不可能只有一个User表,现在增加一个部门表(Department表),就要用到抽象工厂模式了。
增加Department类:
class Department
{
private int _id;
private String _deptName;
public int get_id() {
return _id;
}
public void set_id(int _id) {
this._id = _id;
}
public String get_deptName() {
return _deptName;
}
public void set_deptName(String _deptName) {
this._deptName = _deptName;
}
}
IDepartment接口
interface IDepartment
{
void Insert(Department department);
Department GetDepartment(int id);
}
1
2
3
4
5
6
SqlserverDepartment类和AccessDepartment类
class SqlserverDepartment implements IDepartment
{
public void Insert(Department department)
{
System.out.println(“在Sqlserver中给Department表增加一条记录”);
}
public Department GetDepartment(int id)
{
System.out.println("在Sqlserver中根据ID得到Department表一条记录");
return null;
}
}
class AccessDepartment implements IDepartment
{
public void Insert(Department department)
{
System.out.println(“在Access中给Department表增加一条记录”);
}
public Department GetDepartment(int id)
{
System.out.println("在Access中根据ID得到Department表一条记录");
return null;
}
}
对于抽象工厂类和具体工厂类,只需在类内增加一个工厂接口并在具体工厂中实现:
//IFactory接口
interface IFactory
{
IUser CreateUser();
IDepartment CreateDepartment();//增加的接口方法
}
//SqlServerFactory类
class SqlServerFactory implements IFactory
{
public IUser CreateUser()
{
return new SqlserverUser();
}
public IDepartment CreateDepartment()
{
return new SqlserverDepartment();
}
}
//AccessFactory类
class AccessFactory implements IFactory
{
public IUser CreateUser()
{
return new AccessUser();
}
public IDepartment CreateDepartment()
{
return new AccessDepartment();
}
}
客户端代码:
User user = new User();
Department dept = new Department();
//IFacotory factory = new SqlserverFactory();
//只需确定实例化哪一个数据库访问对象给factory
IFacotory factory = new AccessFactory();
IUser iu = factory.CreateUser();
iu.Insert(user);
iu.GetUser(1);
IDepartment id = factory.CreateDepartment();
id.Insert(dept);
id.GetDepartment(1);
AbstractProductA和AbstractProductB是两个抽象产品,之所以为抽象,是因为它们都有可能有两种不同的实现,就刚才的例子来说就是User和Department,t而ProductA1、ProductA2和ProducB、ProductB2就是对两个抽象产品的具体分类的实现,比如ProductA1 可以理解为是SqlserverUser, 而ProductB1是SqlserverDepartment。IFactory 是一个抽象工厂接口,它里面应该包含所有的产品创建的抽象方法。而ConcreteFactory1和ConcreteFactory2就是具体的工厂了。就像SqlserverFactory和AccessFactory一样。在运行时刻再创建一个ConcreteFactory类的实例,这个具体的工厂再创建具有特定实现的产品对象,也就是说,为创建不同的产品对象,客户端应使用不同的具体工厂。