抽象工廠模式
前序
“這么晚才回來,都11點了。”大鳥看著剛推門而入的小菜問道。
“嗨,沒辦法呀,工作忙。”小菜嘆氣說道。
“怎么會這么忙,加班有點過頭了呀。”
“都是換數據庫惹的禍唄。”
“怎么了?”
“我本來寫好了一個項目,是給一家企業做的電子商務網站,是用SQL Server作為數據庫的,應該說上限后除了開始有些小問題,基本都還可以。而后,公司截到另外一家公司類似需求的項目,但這家公司想省錢,租用了一個空間,只能用Access,不能用SQL Server,于是就要求我今天改造原來那個項目的代碼。”
“哈哈,你的麻煩來了。”
“是呀,那是相當的麻煩。但開始我覺得很簡單呀,因為地球人都知道,SQL Server和Access在ADO.NET上的使用是不同的。我以為只要做一個全體替換就可以了,哪知道,替換后,錯誤百出。”
“以后你還有的是班要加了。”
“為什么?”
“只要網站要維護,比如修改或增加一些功能,你就得改兩個項目吧,至少在數據庫中做改動,響應的程序代碼都要改,甚至和數據庫不想干的代碼也要改,你既然有兩個不同的版本,兩倍的工作量也是必然的。”
“是呀,如果哪天要用Oracle數據庫,估計我要改動的地方更多了。”
“那是當然,Oracle的SQL語法與SQL Server的差別更大。你的改動將是空前的。”
最基本的數據訪問程序
“你先寫一段你原來的數據庫訪問的做法給我看看。”
“那就用‘新增用戶’和‘得到用戶’為例吧。”
#include <stdio.h>
class User
{
public:
int id;
char* name;
};
class SqlserverUser
{
public:
void Insert(User* user)
{
printf("在SQL Server中給User表添加一條記錄\n");
}
User* GetUser(int id)
{
printf("在SQL Server中根據ID得到User表一條記錄\n");
return 0;
}
};
int main()
{
User* user = new User();
SqlserverUser* su = new SqlserverUser();
su->Insert(user);
su->GetUser(1);
delete user;
delete su;
return 0;
}
“我最開始就是這樣寫的,非常簡單。”
“這里之所以不能換數據庫,原因就在于SqlserverUser* su = new SqlserverUser();使得su這個對象被框死在SQL Server上了。如果這里是靈活的,專業點的說法,是多態的,那么在執行‘su->Insert(user);’和‘su->GetUser(1);’時就不用考慮是在用SQL Server還是在用Access了。”
用工廠方法模式的數據訪問程序
#include <stdio.h>
class User
{
public:
int id;
char* name;
};
class IUser
{
public:
virtual void Insert(User* user)=0;
virtual User* GetUser(int id)=0;
};
class SqlserverUser : public IUser
{
public:
virtual void Insert(User* user)
{
printf("在SQL Server中給User表添加一條記錄\n");
}
virtual User* GetUser(int id)
{
printf("在SQL Server中根據ID得到User表一條記錄\n");
return 0;
}
};
class AccessUser : public IUser
{
public:
virtual void Insert(User* user)
{
printf("在Access中給User表添加一條記錄\n");
}
virtual User* GetUser(int id)
{
printf("在Access中根據ID得到User表一條記錄\n");
return 0;
}
};
class IFactory
{
public:
virtual IUser* CreateUser()=0;
};
class SqlServerFactory : public IFactory
{
public:
virtual IUser* CreateUser()
{
return new SqlserverUser();
}
};
class AccessFactory : public IFactory
{
public:
virtual IUser* CreateUser()
{
return new AccessUser();
}
};
int main()
{
User* user = new User();
IFactory* factory = new SqlServerFactory();
IUser* iu = factory->CreateUser();
iu->Insert(user);
iu->GetUser(1);
delete user;
delete factory;
delete iu;
return 0;
}
“非常好?,F在如果要換數據庫,只需要把new SqlServerFactory()改成new AccessFactory(),此時由于多態的關系,使得聲明IUser接口的對象iu實現根本不知道是在訪問哪個數據庫,卻可以在運行時很好的完成工作,這就是所謂的業務邏輯與數據訪問的解耦。”
“但是,大鳥,這樣寫,代碼里還是有指明‘new SqlServerFactory()’呀,我要改的地方,依然很多。”
“這個先不急,待會再說,問題沒有完全解決,你的數據庫里不可能只有一個User表吧,很可能有其他表,比如增加部門表(Department表),此時如何辦呢?”
抽象工廠模式
客戶類和工廠類分開。消費者任何時候需要某套產品集合時,只需向抽象工廠請求即可。抽象工廠會再向具體的工廠生產出符合產品集規格的產品。
實現方式(UML類圖)

實現代碼
#include <stdio.h>
class User
{
public:
int id;
char* name;
};
class Department
{
public:
int id;
char* deptname;
};
// User表接口
class IUser
{
public:
virtual void Insert(User* user)=0;
virtual User* GetUser(int id)=0;
};
// Department表接口
class IDepartment
{
public:
virtual void Insert(Department* department)=0;
virtual Department* GetDepartment(int id)=0;
};
class SqlserverUser : public IUser
{
public:
virtual void Insert(User* user)
{
printf("在SQL Server中給User表添加一條記錄\n");
}
virtual User* GetUser(int id)
{
printf("在SQL Server中根據ID得到User表一條記錄\n");
return 0;
}
};
class AccessUser : public IUser
{
public:
virtual void Insert(User* user)
{
printf("在Access中給User表添加一條記錄\n");
}
virtual User* GetUser(int id)
{
printf("在Access中根據ID得到User表一條記錄\n");
return 0;
}
};
class SqlserverDepartment : public IDepartment
{
public:
virtual void Insert(Department* department)
{
printf("在SQL Server中給Department表增加一條記錄\n");
}
virtual Department* GetDepartment(int id)
{
printf("在SQL Server中根據ID得到Department表一條記錄\n");
return 0;
}
};
class AccessDepartment : public IDepartment
{
public:
virtual void Insert(Department* department)
{
printf("在Access中給Department表增加一條記錄\n");
}
virtual Department* GetDepartment(int id)
{
printf("在Access中根據ID得到Department表一條記錄\n");
return 0;
}
};
// IFactory接口
class IFactory
{
public:
virtual IUser* CreateUser()=0;
virtual IDepartment* CreateDepartment()=0;
};
class SqlServerFactory : public IFactory
{
public:
virtual IUser* CreateUser()
{
return new SqlserverUser();
}
virtual IDepartment* CreateDepartment()
{
return new SqlserverDepartment();
}
};
class AccessFactory : public IFactory
{
public:
virtual IUser* CreateUser()
{
return new AccessUser();
}
virtual IDepartment* CreateDepartment()
{
return new AccessDepartment();
}
};
int main()
{
User* user = new User();
Department* dept = new Department();
IFactory* factory = new AccessFactory();
IUser* iu = factory->CreateUser();
iu->Insert(user);
iu->GetUser(1);
IDepartment* id = factory->CreateDepartment();
id->Insert(dept);
id->GetDepartment(1);
delete user;
delete dept;
delete factory;
delete iu;
delete id;
return 0;
}