一,抽象工厂模式
1.1,最基本的数据访问程序
class User
{
private int id;
private string name;
};
class SqlServerUser
{
public void insert(User &user)
{
// 在SQL Server中给User表增加一条记录
}
public void getUser(int id)
{
// 根据id从User表中获取一条记录
}
}
// 客户端代码
static void main()
{
User *pUser = new User();
SqlServerUser *pSu = new SqlServerUser();
pSu->insert(pUser); // 插入一条记录到User表
pSu->getUser(1); // 获取id为1的user
}
程序分析:
之所以不能直接更换数据库,因为
SqlServerUser *pSu = new SqlServerUser()
把SQL Server数据库硬编码到程序里。
1.2,使用工厂模式的数据访问程序
定义IUser接口,解除与具体数据库访问的耦合
定义IFactory接口,定义一个创建访问User表对象的抽象的工厂接口
class SqlServerFactory : public IFactory
{
public IUser *createUser()
{
return new SqlServerUser();
}
}
class AccessFactory : public IFactory
{
public IUser *createUser()
{
return new AccessUser();
}
}
// 客户端代码
static void main()
{
User *pUser = new User();
IFactory *pFactory = new SqlServerFactory();
IUser *pIU = pFactory->createUser();
pIU->insert(pUser); // 插入一条记录到User表
pIU->getUser(1); // 获取id为1的user
}
程序分析:
由于多态的原因,pIU事先并不知道是在访问哪个数据库,却可以在运行时很好地完成任务,这就是业务逻辑与数据访问的解耦。
1.3,抽象工厂模式的优点与缺点
优点:
- 易于交换产品序列,由于具体的工厂类,例如:IFactory factory = new AccessFactory(),在一个应用中只需要在初始化的时间出现一次,这就使得修改一个应用的具体工厂非常的容易,它只需要改变具体工厂即可使用不同的数据库配置,例如:如果想把数据库切换成SQL Server只需要修改IFactory factory = new SQLServerFactory(),只需要改变具体的工厂类,其它地方都不需要修改,非常的方便。
- 把具体的创建实例的过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户端代码里。
缺点:
- 如果需求增加功能要修改的地方比较的多,例如:新增加一个Department表,至少要增加三个必要的类:IDepartment、SqlserverDepartment、AccessDepartment,同时IFactory、SqlserverFactory、AccessFactory都需要修改,新增加一个类要对已有的三个类进行修改,不符合"开放-封闭"原则,下面是需要增加的代码。
- 如果在程序的很多地方用到IUser,那么在这些用到地方的开始位置要声明IFactory factory = new SQLServerFactory(),当把数据库切换成Access时,就要对程序中所有声明IFactory factory = new SQLServerFactory()语句的地方进行修改。这样不能解决要更换数据库时,改动一处就完全更改的要求。
class IFactory
{
public IUser *createUser();
// 新增代码
IDepartment *createDepartment()
};
class SqlServerFactory : public IFactory
{
public IUser *createUser()
{
return new SqlServerUser();
}
// 新增代码
public IDepartment *createDepartment()
{
return new SqlServerDepartment();
}
};
class AccessFactory : public IFactory
{
public IUser *createUser()
{
return new AccessUser();
}
// 新增代码
public IDepartment *createDepartment()
{
return new AccessDepartment();
}
};
1.4,使用简单工厂来改进抽象工厂
使用DataAccess类替换掉IFactory、SqlserverFactory、AccessFactory三个工厂方法
class DataAccess
{
// 要访问的数据库名称,在这里可以更改成Access
private static 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;
}
}
// 客户端代码
static void main()
{
User *pUser = new User();
IUser *pIU = DataAccess.createUser();
pIU->insert(pUser); // 插入一条记录到User表
pIU->getUser(1); // 获取id为1的user
}
程序分析:
使用DataAccess类替换掉IFactory、SqlserverFactory、AccessFactory三个工厂方法,客户端只需要DataAccess.createUser()或DataAccess.createDepartment()来生成具体的数据库访问实例,客户端没有出现任何一个SQL Server或Access这样的字样,达到了解耦的目的。