抽象工廠模式解析
抽象工廠模式是所有形態的工廠模式中最爲抽象和最具一般性的一種形態。抽象工廠模式是指當有多個抽象角色時,使用的一種工廠模式。抽象工廠模式可以向客戶端提供一個接口,使客戶端在不必指定產品的具體的情況下,創建多個產品族中的產品對象。根據里氏替換原則,任何接受父類型的地方,都應當能夠接受子類型。因此,實際上系統所需要的,僅僅是類型與這些抽象產品角色相同的一些實例,而不是這些抽象產品的實例。換言之,也就是這些抽象產品的具體子類的實例。工廠類負責創建抽象產品的具體子類的實例。(摘自百度百科)
此處不對抽象工廠模式進行詳細的解析,不大理解的讀者可以到網上找相關的知識,可以找到很多的.
代碼實現
溫馨提示:如果此時讀者還沒由安裝mysql數據庫那就先把數據庫安裝好.
// "Factory.h"
#ifndef __FACTORY_H__
#define __FACTORY_H__
#include <iostream>
#include <memory>
#include "Product.h"
class CIFactory {
public:
virtual std::shared_ptr<CIUser> CreateUser() = 0;
};
#endif
解析: 這個頭文件封裝了一個工廠的抽象類,裏面有一個虛函數,其中使用C++11的智能指針shared_ptr來管理返回的對象指針,而CIUser則是數據庫的抽象類.
// "MysqlFactory.h"
#ifndef __MYSQLFACTORY_H__
#define __MYSQLFACTORY_H__
#include "Factory.h"
#include "MysqlProduct.h"
// mysql工廠
class sqlFactory : public CIFactory
{
public:
std::shared_ptr<CIUser> CreateUser() {
return std::shared_ptr<CIUser>(new SqlServerUser());
}
};
#endif
解析: 該頭文件實現了虛基類的派生類,想要編寫sql server等數據庫工廠時只需要仿照此處的代碼即可,上面這個代碼值針對mysql數據庫的,使用抽象類CIUser指針來接收派生類SqlServerUser對象指針.
// "Product.h"
#ifndef __PRODUCT_H__
#define __PRODUCT_H__
#include <string>
#include <memory>
class User
{
public:
int Id() const { return id_; }
void SetId(int val) { id_ = val; }
std::string Name() const { return name_; }
void SetName(std::string val) { name_ = val; }
private:
int id_;
std::string name_;
};
class CIUser
{
public:
virtual bool InitSql() = 0;
virtual bool ConnSql(std::string host,
std::string user,
std::string pwd,
std::string db_name) = 0;
virtual bool SelectSql(std::string sql) = 0;
virtual bool InsertSql(std::string sql) = 0;
virtual bool DelSql(std::string sql) = 0;
virtual void Insert(User user) = 0;
virtual User getuser(int id) const = 0;
};
#endif
解析: Product.h頭文件主要是對象接口,例如我在此處要實現的是數據庫操作的抽象工廠,那麼這個頭文件裏面我要寫的就是數據庫的虛基類,提供派生類使用.
// "MysqlProduct.h"
#ifndef __MYSQLPRODUCT_H__
#define __MYSQLPRODUCT_H__
#include "Product.h"
#include <iostream>
#include <mysql/mysql.h>
class SqlServerUser : public CIUser
{
public:
SqlServerUser() {
InitSql();
}
~SqlServerUser() {
if (m_pConnection != NULL) {
mysql_close(m_pConnection);
m_pConnection = NULL;
}
}
bool InitSql() {
m_pConnection = mysql_init(NULL);
if (m_pConnection == NULL) {
std::cout << "init mysql error!" << std::endl;
return false;
}
return true;
}
bool ConnSql(std::string host,
std::string user,
std::string pwd,
std::string db_name) {
// 建立數據庫連接
m_pConnection = mysql_real_connect(m_pConnection, host.c_str(),
user.c_str(), pwd.c_str(), db_name.c_str(), 0, NULL, 0);
if (NULL == m_pConnection)
{
std::cout << "Error: " << mysql_error(m_pConnection);
return false;
}
// Linux下 Windows下使用mysql_query(connection, "SET NAMES GB2312"); 用以解決讀取數據庫中文數據時亂碼
mysql_query(m_pConnection, "SET NAMES UTF8");
return true;
}
bool SelectSql(std::string sql) {
// 執行sql語句
if (mysql_query(m_pConnection, sql.c_str()))
{
std::cout << "Select Error: " << mysql_error(m_pConnection);
return false;
}
// 獲取數據
result = mysql_use_result(m_pConnection);
for (int i = 0; i < mysql_field_count(m_pConnection); ++i)
{
// 獲取下一行
row = mysql_fetch_row(result);
if (row <= 0)
break;
for (int j = 0; j < mysql_num_fields(result); ++j)
{
std::cout << row[j] << " ";
}
std::cout << std::endl;
}
mysql_free_result(result); // 釋放結果集的內存
return true;
}
bool InsertSql(std::string sql) {
if (mysql_query(m_pConnection, sql.c_str()))
{
std::cout << "Insert Error: " << mysql_error(m_pConnection);
return false;
}
return true;
}
bool DelSql(std::string sql) {
if (mysql_query(m_pConnection, sql.c_str()))
{
std::cout << "Del Error: " << mysql_error(m_pConnection);
return false;
}
return true;
}
void Insert(User user) {
std::cout << "sql server insert a record" << std::endl;
}
User getuser(int id) const {
std::cout << "get user from sql server" << std::endl;
return User();
}
private:
MYSQL *m_pConnection;
MYSQL_RES *result;
MYSQL_ROW row;
};
#endif
解析:MysqlProduct.h是數據庫接口的派生類,裏面主要封裝了對mysql數據庫的操作,裏面的代碼都比較簡單就不做詳細介紹了.像擴展其他數據庫的時候只需要仿照此頭文件就可以了.
下面我們來實現main.cc文件來測試上面的抽象工廠.
溫馨提示:此處我建了了一個數據表叫user,裏面有三個字段:user_id;name;sex
#include "../Include/MysqlFactory.h"
#include "../Include/MysqlProduct.h"
#include <iostream>
#include <memory>
using namespace std;
int main(void)
{
// 抽象工廠的方式獲取mysql工廠
shared_ptr<CIFactory> factory(new sqlFactory);
shared_ptr<CIUser> iuser = factory->CreateUser();
// 連接mysql數據庫
if (iuser->ConnSql("數據庫IP地址如:localhost", "用戶名如:root", "password", "數據庫名")) {
std::cout << "connect mysql success!" << std::endl;
}
std::string sql = "SELECT * FROM user WHERE user_id = 1";
iuser->SelectSql(sql);
// 插入語句
sql = "INSERT INTO user(name, sex) VALUES ('jack', '男')";
if (iuser->InsertSql(sql)) {
std::cout << "insert success!" << std::endl;
}
system("pause");
return 0;
}
CMake編寫
下面來看看我的文件目錄吧:
- SqlFactory
- build
- Include
- Factory.h
- MysqlFactory.h
- Product.h
- MysqlProduct.h
- src
- main.cc
- CMakeLists.txt
- CMakeLists.txt
我們先來看看SqlFactory目錄下的CMakeLists.txt
PROJECT(SQLTEST)
ADD_SUBDIRECTORY(src)
下面來編寫src目錄下的CMakeLists.txt腳本
SET(SOULIST_SRC main.cc)
ADD_EXECUTABLE(test ${SOULIST_SRC})
TARGET_LINK_LIBRARIES(test mysqlclient)
# 用以編譯shared_ptr
if(UNIX)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=gnu++0x")
endif()
這時我的代碼跟腳本就已經全部完成了,下面我們來運行代碼吧
將終端來到SqlFactory/build目錄下,編輯:
cmake ..
make
這時在build目錄下的src文件夾下就可以看到可執行文件test了,編輯:
./test
即可運行程序了.