設(shè)計(jì)模式最大的作用就是在變化和穩(wěn)定中間尋找隔離點(diǎn),然后分離它們,從而管理變化。將變化像小兔子一樣關(guān)到籠子里,讓它在籠子里隨便跳,而不至于跳出來把你整個(gè)房間給污染掉。
設(shè)計(jì)思想
提供一個(gè)接口,讓該接口負(fù)責(zé)創(chuàng)建一系列“相關(guān)或者相互依賴的對(duì)象”,無需指定他們具體的類。
動(dòng)機(jī)
在軟件系統(tǒng)中,經(jīng)常面臨著“一系列相互依賴的對(duì)象”的創(chuàng)建工作;同時(shí),由于需求的變化,往往存在更多系列對(duì)象的創(chuàng)建工作。
如何應(yīng)對(duì)這種變化?如何繞過常規(guī)的對(duì)象創(chuàng)建方法(new),提供一種“封裝機(jī)制”來避免客戶程序和這種“多系列具體對(duì)象創(chuàng)建工作”的緊耦合?
如果沒有應(yīng)對(duì)“多系列對(duì)象構(gòu)建”的需求變化,則沒有必要使用Abstract Factory模式,這時(shí)候使用簡單的工廠完全可以。
“系列對(duì)象”指的是在某一特定系列下的對(duì)象之間有相互依賴或作用關(guān)系。不同系列的對(duì)象之間不能相互依賴。
Abstract Factory模式主要在于應(yīng)對(duì)“新系列”的需求變動(dòng)。其缺點(diǎn)在于難以應(yīng)對(duì)“新對(duì)象”的需求變動(dòng)。
抽象工廠和工廠方法非常相像,區(qū)別就在于抽象工廠需要一系列對(duì)應(yīng)的對(duì)象,而工廠方法就是唯一對(duì)象,因此工廠方法也可以理解成抽象工廠的一個(gè)特例。
業(yè)務(wù)場景
要對(duì) SQL Server 數(shù)據(jù)庫進(jìn)行操作,需要有 Connection,Command,DataReader等一系列配套的操作。而當(dāng)需要更換數(shù)據(jù)庫的時(shí)候,也是這套操作
如何提高代碼復(fù)用性
一個(gè)非常直觀的思路是:
class EmployeeDAO {
public:
vector<EmployeeDO> GetEmployees() {
SqlConnection* connection = new SqlConnection();
connection->ConnectionString("...");
SqlCommand* command = new SqlCommand();
command->CommandText("...");
command->SetConnection(connection);
SqlDataReader* reader = command->ExecuteReader();
while (reader->Read()) {
}
}
};
看見這些熟悉的代碼:
SqlConnection* connection = new SqlConnection();
SqlCommand* command = new SqlCommand();
如果你看過前面的工廠方法模式,你會(huì)很自然的聯(lián)想到那個(gè),然后將代碼改進(jìn)成這樣:
// 數(shù)據(jù)庫訪問有關(guān)的基類
class IDBConnection {};
class IDBConnectionFactory {
public:
virtual IDBConnection* CreateDBConnection() = 0;
};
class IDBCommand {};
class IDBCommandFactory {
public:
virtual IDBCommand* CreateDBCommand() = 0;
};
class IDataReader {};
class IDataReaderFactory {
public:
virtual IDataReader* CreateDataReader() = 0;
};
// 支持SQL Server
class SqlConnection : public IDBConnection {};
class SqlConnectionFactory : public IDBConnectionFactory {};
class SqlCommand : public IDBCommand {};
class SqlCommandFactory : public IDBCommandFactory {};
class SqlDataReader : public IDataReader {};
class SqlDataReaderFactory : public IDataReaderFactory {};
// 支持Oracle
class OracleConnection : public IDBConnection {};
class OracleConnectionFactory : public IDBConnectionFactory {};
class OracleCommand : public IDBCommand {};
class OracleCommandFactory : public IDBCommandFactory {};
class OracleDataReader : public IDataReader {};
class OracleDataReaderFactory : public IDataReaderFactory {};
class EmployeeDAO {
IDBConnectionFactory* dbConnectionFactory;
IDBCommandFactory* dbCommandFactory;
IDataReaderFactory* dataReaderFactory;
public:
vector<EmployeeDO> GetEmployees() {
IDBConnection* connection = dbConnectionFactory->CreateDBConnection();
connection->ConnectionString("...");
IDBCommand* command = dbCommandFactory->CreateDBCommand();
command->CommandText("...");
command->SetConnection(connection); // 關(guān)聯(lián)性
IDBDataReader* reader = command->ExecuteReader(); // 關(guān)聯(lián)性
while (reader->Read()) {
}
}
};
有沒有解決問題呢?確實(shí)解決了,但是如果細(xì)心一點(diǎn),你會(huì)發(fā)現(xiàn):這三個(gè)工廠實(shí)例化出來的對(duì)象應(yīng)該是一套的:SQL只能用SQL的connection,command以及dataReader,MYSQL只能用MYSQL的,也就是說在構(gòu)造EmployeeDAO的時(shí)候,雖然需要傳入三個(gè)工廠對(duì)象:dbConnectionFactory,dbCommandFactory,dataReaderFactory,但是這三個(gè)對(duì)象卻必須是一套的,這就帶來了問題:1. 用戶有可能傳錯(cuò)對(duì)象;2.既然必須是一套的,那么完全可以將其封裝成一個(gè)對(duì)象傳進(jìn)來文章來源:http://www.zghlxwxcb.cn/news/detail-693783.html
于是,便有了抽象工廠模式:將三個(gè)配套的操作再封裝成一個(gè)類,避免產(chǎn)生配套錯(cuò)誤文章來源地址http://www.zghlxwxcb.cn/news/detail-693783.html
代碼案例
// 數(shù)據(jù)庫訪問有關(guān)的基類
class IDBConnection {};
class IDBCommand {};
class IDataReader {};
// 三個(gè)操作,綁定到一起
// 此處是這個(gè)模式的穩(wěn)定部分
class IDBFactory {
public:
virtual IDBConnection* CreateDBConnection() = 0;
virtual IDBCommand* CreateDBCommand() = 0;
virtual IDataReader* CreateDataReader() = 0;
};
// 支持SQL Server
class SqlConnection : public IDBConnection {};
class SqlCommand : public IDBCommand {};
class SqlDataReader : public IDataReader {};
class SqlDBFactory : public IDBFactory {
public:
virtual IDBConnection* CreateDBConnection() = 0;
virtual IDBCommand* CreateDBCommand() = 0;
virtual IDataReader* CreateDataReader() = 0;
};
// 支持Oracle
class OracleConnection : public IDBConnection {};
class OracleCommand : public IDBCommand {};
class OracleDataReader : public IDataReader {};
class OracleDBFactory : public IDBFactory {
public:
virtual IDBConnection* CreateDBConnection() = 0;
virtual IDBCommand* CreateDBCommand() = 0;
virtual IDataReader* CreateDataReader() = 0;
};
class EmployeeDAO {
// 保證是同一個(gè)工廠
// 是一個(gè) family
IDBFactory* dbFactory;
public:
vector<EmployeeDO> GetEmployees() {
IDBConnection* connection = dbFactory->CreateDBConnection();
connection->ConnectionString("...");
IDBCommand* command = dbFactory->CreateDBCommand();
command->CommandText("...");
command->SetConnection(connection); // 關(guān)聯(lián)性
IDBDataReader* reader = command->ExecuteReader(); // 關(guān)聯(lián)性
while (reader->Read()) {
}
}
};
到了這里,關(guān)于【設(shè)計(jì)模式】Head First 設(shè)計(jì)模式——抽象工廠模式 C++實(shí)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!