源码可以在这里找到 大话设计模式C++版
//User.h
#include
class User
{
private:
int m_id;
QString m_name;
public:
int getId() {
return m_id;
}
void setId(int id) {
m_id = id;
}
QString getName() {
return m_name;
}
void setName(QString name) {
m_name = name;
}
};
//SqlserverUser.h
#pragma execution_character_set("utf-8")
#include "User.h"
#include
#include
using namespace std;
class SqlserverUser
{
public:
void insertUser(shared_ptr<User> user) {
qDebug() << "在SQL Server中给User表增加一条记录";
}
shared_ptr<User> getUser(int id) {
qDebug() << "在SQL Server中根据ID得到User表一条记录";
return nullptr;
}
};
//main.cpp
#include "User.h"
#include "SqlserverUser.h"
int main(int argc, char *argv[])
{
auto user = shared_ptr<User>(new User());
auto su = shared_ptr<SqlserverUser>(new SqlserverUser()); //与SQL Server耦合
su->insertUser(user); //插入用户
su->getUser(1); //得到ID为1的用户
return 0;
}
运行结果:
在SQL Server中给User表增加一条记录
在SQL Server中根据ID得到User表一条记录
问题:这里之所以不能换数据库,原因就在于 auto su = shared_ptr
使得su这个对象被框死在 SQL Server
上了。如果这里是灵活的,多态的,那么在执行 su->insertUser(user);
和 su->getUser(1);
时就不用考虑是在用 SQL Server
还是 Access
了。
解决方案:用 工厂方法模式
来封装 new SqlserverUser()
所造成的变化,工厂方法模式是定义一个用于创建对象的接口,让子类决定实例化哪一个类。
//IUser.h 用户接口类,用于客户端访问,解除与具体数据库访问的耦合
#include "User.h"
#include
using namespace std;
class IUser
{
public:
IUser();
virtual void insertUser(shared_ptr<User> user) = 0;
virtual shared_ptr<User> getUser(int id) = 0;
};
//SqlserverUser.h 具体数据库类
#pragma execution_character_set("utf-8")
#include "IUser.h"
#include
using namespace std;
class SqlserverUser : public IUser
{
public:
virtual void insertUser(shared_ptr<User> user) override {
qDebug() << "在SQL Server中给User表增加一条记录";
}
virtual shared_ptr<User> getUser(int id) override {
qDebug() << "在SQL Server中根据ID得到User表一条记录";
return nullptr;
}
};
//AccessUser.h 具体数据库类
#pragma execution_character_set("utf-8")
#include "IUser.h"
#include
using namespace std;
class AccessUser : public IUser
{
public:
virtual void insertUser(shared_ptr<User> user) override {
qDebug() << "在Access中给User表增加一条记录";
}
virtual shared_ptr<User> getUser(int id) override {
qDebug() << "在Access中根据ID得到User表一条记录";
return nullptr;
}
};
//IFactory.h 抽象工厂接口
#include "IUser.h"
class IFactory
{
public:
virtual shared_ptr<IUser> createUser() = 0;
};
//SqlServerFactory.h 具体工厂类
#include "IFactory.h"
class SqlServerFactory : public IFactory
{
public:
virtual shared_ptr<IUser> createUser() override {
return shared_ptr<IUser>(new SqlserverUser());
}
};
//AccessFactory.h 具体工厂类
#include "IFactory.h"
class AccessFactory : public IFactory
{
public:
virtual shared_ptr<IUser> createUser() override {
return shared_ptr<IUser>(new AccessUser());
}
};
//main.cpp 客户端代码
#include "User.h"
#include "IFactory.h"
#include "SqlServerFactory.h"
int main(int argc, char *argv[])
{
shared_ptr<User> user = shared_ptr<User>(new User());
//若要更改成Access数据库,只需要将本句改成shared_ptr(new AccessFactory());
shared_ptr<IFactory> factory = shared_ptr<SqlServerFactory>(new SqlServerFactory());
auto iu = factory->createUser();
iu->insertUser(user);
iu->getUser(1);
return 0;
}
现在如果要换数据库,只需更换 SqlServerFactory类
为 AccessFactory类
就可以了。但是数据库里通常不会只有一个 User表
,如果要增加部门表 Department表
,怎么办?
//Department.h
#include
class Department
{
private:
int m_id;
QString m_name;
public:
int getId() {
return m_id;
}
void setId(int id) {
m_id = id;
}
QString getName() {
return m_name;
}
void setName(QString name) {
m_name = name;
}
};
//IDepartment.h 部门接口类,用于客户端访问,解除与具体数据库访问的耦合
#include "Department.h"
#include
using namespace std;
class IDepartment
{
public:
virtual void insertDepartment(shared_ptr<Department> department) = 0;
virtual shared_ptr<Department> getDepartment(int id) = 0;
};
//SqlserverDepartment.h
#pragma execution_character_set("utf-8")
#include "IDepartment.h"
#include
class SqlserverDepartment : public IDepartment
{
public:
virtual void insertDepartment(shared_ptr<Department> department) override {
qDebug() << "在SQL Server中给Department表增加一条记录";
}
virtual shared_ptr<Department> getDepartment(int id) override {
qDebug() << "在SQL Server中根据ID得到Department表一条记录";
return nullptr;
}
};
//AccessDepartment.h
#pragma execution_character_set("utf-8")
#include "IDepartment.h"
#include
class AccessDepartment : public IDepartment
{
public:
virtual void insertDepartment(shared_ptr<Department> department) override {
qDebug() << "在Access中给Department表增加一条记录";
}
virtual shared_ptr<Department> getDepartment(int id) override {
qDebug() << "在Access中根据ID得到Department表一条记录";
return nullptr;
}
};
//IFactory.h 抽象工厂接口
#include "IUser.h"
#include "IDepartment.h"
class IFactory
{
public:
virtual shared_ptr<IUser> createUser() = 0;
virtual shared_ptr<IDepartment> createDepartment() = 0;
};
//SqlServerFactory.h
#include "IFactory.h"
class SqlServerFactory : public IFactory
{
public:
virtual shared_ptr<IUser> createUser() override {
return shared_ptr<IUser>(new SqlserverUser());
}
virtual shared_ptr<IDepartment> createDepartment() override {
return shared_ptr<IDepartment>(new SqlserverDepartment());
}
};
//AccessFactory.h
#include "IFactory.h"
class AccessFactory : public IFactory
{
public:
AccessFactory();
virtual shared_ptr<IUser> createUser() override {
return shared_ptr<IUser>(new AccessUser());
}
virtual shared_ptr<IDepartment> createDepartment() override {
return shared_ptr<AccessDepartment>(new AccessDepartment());
}
};
//main.cpp 客户端代码
#include "User.h"
#include "Department.h"
#include "IFactory.h"
#include "AccessFactory.h"
int main(int argc, char *argv[])
{
shared_ptr<User> user = shared_ptr<User>(new User());
shared_ptr<Department> dept = shared_ptr<Department>(new Department());
shared_ptr<IFactory> factory = shared_ptr<AccessFactory>(new AccessFactory());
auto iu = factory->createUser(); //此时已与具体的数据库访问解除了依赖
iu->insertUser(user);
iu->getUser(1);
auto id = factory->createDepartment(); //此时已与具体的数据库访问解除了依赖
id->insertDepartment(dept);
id->getDepartment(1);
return 0;
}
运行结果:
在Access中给User表增加一条记录
在Access中根据ID得到User表一条记录
在Access中给Department表增加一条记录
在Access中根据ID得到Department表一条记录
上面就是抽象工厂模式的代码了,大话设计模式中,还用简单工厂对抽象工厂进行改造,并用 反射
代替简单工厂的 switch-case
,这使用 C#语言
是很容易实现的,C++
原生不支持 反射
,因此等以后学会 C++反射
之后再来实现这部分的代码。
new
,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。它是接口抽象之后的第一步工作。//数据库访问有关的基类
class IDBConnection {};
class IDBCommand {};
class IDBDataReader {};
class IDBFactory {
public:
virtual IDBConnection* CreateDBConnection() = 0;
virtual IDBCommand* CreateDBCommand() = 0;
virtual IDBDataReader* CreateDBDataReader() = 0;
};
//支持SQL Server
class SqlConnection : public IDBConnection {};
class SqlCommand : public IDBCommand {};
class SqlDataReader : public IDBDataReader {};
class SqlFactory : public IDBFactory {
public:
virtual IDBConnection* CreateDBConnection() override {
return new SqlConnection();
}
virtual IDBCommand* CreateDBCommand() override {
return new SqlCommand();
}
virtual IDBDataReader* CreateDBDataReader() override {
return new SqlDataReader();
}
};
//支持Oracle
class OracleConnection : public IDBConnection {};
class OracleCommand : public IDBCommand {};
class OracleDataReader : public IDBDataReader {};
class EmployeeDA0
{
IDBFactory* dbFactory;
public:
vector<EmployeeDA0> GetEmployees() {
IDBConnection* connection = dbFactory->CreateDBConnection();
connection->ConnectionString("...");
IDBCommand* command = dbFactory->CreateDBCommand();
command->CommandText("...");
command->SetConnect(connection); //关联性
IDBDataReader* reader = command->ExecuteReader(); //关联性
while (reader->Read()) {
}
}
};
提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。——《设计模式》GoF