抽象工廠模式
前序
“這么晚才回來,都11點(diǎn)了。”大鳥看著剛推門而入的小菜問道。
“嗨,沒辦法呀,工作忙。”小菜嘆氣說道。
“怎么會(huì)這么忙,加班有點(diǎn)過頭了呀。”
“都是換數(shù)據(jù)庫(kù)惹的禍唄。”
“怎么了?”
“我本來寫好了一個(gè)項(xiàng)目,是給一家企業(yè)做的電子商務(wù)網(wǎng)站,是用SQL Server作為數(shù)據(jù)庫(kù)的,應(yīng)該說上限后除了開始有些小問題,基本都還可以。而后,公司截到另外一家公司類似需求的項(xiàng)目,但這家公司想省錢,租用了一個(gè)空間,只能用Access,不能用SQL Server,于是就要求我今天改造原來那個(gè)項(xiàng)目的代碼。”
“哈哈,你的麻煩來了。”
“是呀,那是相當(dāng)?shù)穆闊5_始我覺得很簡(jiǎn)單呀,因?yàn)榈厍蛉硕贾溃?/span>SQL Server和Access在ADO.NET上的使用是不同的。我以為只要做一個(gè)全體替換就可以了,哪知道,替換后,錯(cuò)誤百出。”
“以后你還有的是班要加了。”
“為什么?”
“只要網(wǎng)站要維護(hù),比如修改或增加一些功能,你就得改兩個(gè)項(xiàng)目吧,至少在數(shù)據(jù)庫(kù)中做改動(dòng),響應(yīng)的程序代碼都要改,甚至和數(shù)據(jù)庫(kù)不想干的代碼也要改,你既然有兩個(gè)不同的版本,兩倍的工作量也是必然的。”
“是呀,如果哪天要用Oracle數(shù)據(jù)庫(kù),估計(jì)我要改動(dòng)的地方更多了。”
“那是當(dāng)然,Oracle的SQL語(yǔ)法與SQL Server的差別更大。你的改動(dòng)將是空前的。”
最基本的數(shù)據(jù)訪問程序
“你先寫一段你原來的數(shù)據(jù)庫(kù)訪問的做法給我看看。”
“那就用‘新增用戶’和‘得到用戶’為例吧。”
#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中根據(jù)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;
}
“我最開始就是這樣寫的,非常簡(jiǎn)單。”
“這里之所以不能換數(shù)據(jù)庫(kù),原因就在于SqlserverUser* su = new SqlserverUser();使得su這個(gè)對(duì)象被框死在SQL Server上了。如果這里是靈活的,專業(yè)點(diǎn)的說法,是多態(tài)的,那么在執(zhí)行‘su->Insert(user);’和‘su->GetUser(1);’時(shí)就不用考慮是在用SQL Server還是在用Access了。”
用工廠方法模式的數(shù)據(jù)訪問程序
#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中根據(jù)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中根據(jù)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;
}
“非常好。現(xiàn)在如果要換數(shù)據(jù)庫(kù),只需要把new SqlServerFactory()改成new AccessFactory(),此時(shí)由于多態(tài)的關(guān)系,使得聲明IUser接口的對(duì)象iu實(shí)現(xiàn)根本不知道是在訪問哪個(gè)數(shù)據(jù)庫(kù),卻可以在運(yùn)行時(shí)很好的完成工作,這就是所謂的業(yè)務(wù)邏輯與數(shù)據(jù)訪問的解耦。”
“但是,大鳥,這樣寫,代碼里還是有指明‘new SqlServerFactory()’呀,我要改的地方,依然很多。”
“這個(gè)先不急,待會(huì)再說,問題沒有完全解決,你的數(shù)據(jù)庫(kù)里不可能只有一個(gè)User表吧,很可能有其他表,比如增加部門表(Department表),此時(shí)如何辦呢?”
抽象工廠模式
客戶類和工廠類分開。消費(fèi)者任何時(shí)候需要某套產(chǎn)品集合時(shí),只需向抽象工廠請(qǐng)求即可。抽象工廠會(huì)再向具體的工廠生產(chǎn)出符合產(chǎn)品集規(guī)格的產(chǎn)品。
實(shí)現(xiàn)方式(UML類圖)

實(shí)現(xiàn)代碼
#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中根據(jù)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中根據(jù)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中根據(jù)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中根據(jù)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;
}
運(yùn)行結(jié)果

所有文件打包下載
posted on 2011-06-26 22:19
lwch 閱讀(3340)
評(píng)論(2) 編輯 收藏 引用 所屬分類:
設(shè)計(jì)模式