在学习侯捷老师的有关设计模式的课程(李建忠老师主讲)中,老师对23种设计模式的有自己的划分,如下。所以老师讲解是按照这种顺序讲解。
对象创建:
和工厂模式不同,它解决的是单一的对象创建工作。抽象工厂模式解决的是“一系列相互依赖
的对象”的创建工作。
设计模式之工厂模式(Factor Method)
先给代码再说明:
#include
#include
using namespace std;
//database connection
class IDBConnection
{
public:
virtual void ConnectionString() = 0;
};
class SqlConnection : public IDBConnection
{
public:
void ConnectionString(){ cout << "Sql connection" << endl; }
};
class MysqlConnection : public IDBConnection
{
public:
void ConnectionString(){ cout << "Mysql connection" << endl; }
};
//database command
class IDBCommand
{
public:
virtual void CommandText() = 0;
virtual void SetConnection(IDBConnection* connect) = 0;
};
class SqlCommand : public IDBCommand
{
public:
void CommandText(){ cout << "Sql command text" << endl; }
void SetConnection(IDBConnection* connect){ cout << "set connection with "; connect->ConnectionString(); }
};
class MysqlCommand : public IDBCommand
{
public:
void CommandText(){ cout << "Mysql command text" << endl; }
void SetConnection(IDBConnection* connect){ cout << "set connection with "; connect->ConnectionString(); }
};
/***********工厂介入 start*****************************/
//抽象工厂
class IDBFactor
{
public:
virtual IDBConnection* creatDBConnection() = 0;
virtual IDBCommand* creatDBCommand() = 0;
};
//sql 工厂
class SqlFactor : public IDBFactor
{
public:
virtual IDBConnection* creatDBConnection()
{
return new SqlConnection;
}
virtual IDBCommand* creatDBCommand()
{
return new SqlCommand;
}
};
//Mysql 工厂
class MysqlFactor : public IDBFactor
{
public:
virtual IDBConnection* creatDBConnection()
{
return new MysqlConnection;
}
virtual IDBCommand* creatDBCommand()
{
return new MysqlCommand;
}
};
/***********工厂介入 end*****************************/
class EmployeeDAO
{
IDBFactor* dbfactor;
public:
EmployeeDAO(){}
EmployeeDAO(IDBFactor* _dbfactor) : dbfactor(_dbfactor){}
void GetEmployees(){
//IDBConnection* connection = new SqlConnection();
IDBConnection* connection = dbfactor->creatDBConnection();
connection->ConnectionString();
//IDBCommand* command = new SqlCommand();
IDBCommand* command = dbfactor->creatDBCommand();
command->CommandText();
command->SetConnection(connection);
}
};
int main()
{
EmployeeDAO e(new MysqlFactor);
e.GetEmployees();
EmployeeDAO e1(new SqlFactor);
e1.GetEmployees();
system("pause");
return 0;
}
EmployeeDAO
类中,由于Connection和Command是相互依赖,所以我们把这两个对象的创建放在一个抽象工厂IDBFactor
,然后分别有SqlFactor
和MysqlFactor
两个具体工厂,各自创建自己的Connection和Command(SqlConnection、SqlCommand和MysqlConnection、MysqlCommand
)相关类。
使用工厂模式的影响:
如果用工厂模式分别生成这两个对象,那么可能会存在这样一种情况:即我们生成了一个SqlConnection
,但是command却是MysqlCommand
,代码如下:
#if 1
#include
#include
using namespace std;
//database connection
class IDBConnection
{
public:
virtual void ConnectionString() = 0;
};
class SqlConnection : public IDBConnection
{
public:
void ConnectionString(){ cout << "Sql connection" << endl; }
};
class MysqlConnection : public IDBConnection
{
public:
void ConnectionString(){ cout << "Mysql connection" << endl; }
};
/***connection工厂***/
class IDBConnectionFactor
{
public:
virtual IDBConnection* creatorIDBConnection() = 0;
};
class SqlConnectionFactor : public IDBConnectionFactor
{
public:
virtual IDBConnection* creatorIDBConnection(){ return new SqlConnection; }
};
class MySqlConnectionFactor : public IDBConnectionFactor
{
public:
virtual IDBConnection* creatorIDBConnection(){ return new MysqlConnection; }
};
/***connection工厂***/
//database command
class IDBCommand
{
public:
virtual void CommandText() = 0;
virtual void SetConnection(IDBConnection* connect) = 0;
};
class SqlCommand : public IDBCommand
{
public:
void CommandText(){ cout << "Sql command text" << endl; }
void SetConnection(IDBConnection* connect){ cout << "Sql set connection with "; connect->ConnectionString(); }
};
class MysqlCommand : public IDBCommand
{
public:
void CommandText(){ cout << "Mysql command text" << endl; }
void SetConnection(IDBConnection* connect){ cout << "Mysql set connection with "; connect->ConnectionString(); }
};
/***Command工厂***/
class IDBCommandFactor
{
public:
virtual IDBCommand* creatorIDBCommand() = 0;
};
class SqlCommandFactor : public IDBCommandFactor
{
public:
virtual IDBCommand* creatorIDBCommand(){ return new SqlCommand; }
};
class MySqlCommandFactor : public IDBCommandFactor
{
public:
virtual IDBCommand* creatorIDBCommand(){ return new MysqlCommand; }
};
/***Command工厂***/
class EmployeeDAO
{
IDBConnectionFactor* connectionfactor;
IDBCommandFactor* commandfactor;
public:
EmployeeDAO(){}
EmployeeDAO(IDBConnectionFactor* _connectionfactor, IDBCommandFactor* _commandfactor)
: connectionfactor(_connectionfactor), commandfactor(_commandfactor){}
void GetEmployees(){
//IDBConnection* connection = new SqlConnection();
IDBConnection* connection = connectionfactor->creatorIDBConnection();
connection->ConnectionString();
//IDBCommand* command = new SqlCommand();
IDBCommand* command = commandfactor->creatorIDBCommand();
command->CommandText();
command->SetConnection(connection);
}
};
int main()
{
EmployeeDAO e(new SqlConnectionFactor, new MySqlCommandFactor);
e.GetEmployees();
system("pause");
return 0;
}
#endif
这里就会有两个工厂数据成员,在客户使用EmployeeDAO
类时,就可能出现下图中创建对象不搭配的情况。
李建忠老师在讲解抽象工厂模式时,并没有提到关于产品族和产品等级这个概念,但是我发现网上很多关于抽象工厂的文章中都提到了这个概念,所以在这里稍微说一下我的理解。
拿案例1举例,我们可以做这样的一个划分:
如果我们增加一个产品族,程序是可以很好扩展,不会违背开闭原则;但是如果我们增加一个产品等级,你会发现就需要修改而不是扩展代码,会违背开闭原则。
这里你可能会比较难区分什么是产品族?什么是产品等级?我的理解就是:
因为抽象工厂模式解决的就是“一系列相互依赖
的对象”的创建工作,所以这系列对象就是一个产品族,不是一族怎么会相互依赖呢!
下面在举一个例子,如下所示是产品族和产品等级。
图片来源:链接
假设我们的客户程序是先打开手机和路由器,再通过手机控制路由器,伪代码如下;
class Client
{
public:
void getWorking(){
generate 手机;
手机start;
generate 路由器;
路由器start;
手机控制路由器;
}
}
代码还是很简单写的,下面一步步写:
下面开始代码:
1.先来写华为手机和路由器的类+Client类并做简单测试(不用抽象工厂模式)
#include
#include
using namespace std;
//手机基类
class IPhone
{
public:
virtual void phoneStart() = 0;
virtual string phoneName() = 0;
};
class HuaweiPhone : public IPhone
{
public:
virtual void phoneStart()
{
cout << "华为手机开机" << endl;
}
virtual string phoneName()
{
return string("华为");
}
};
//路由器基类
class IRouter
{
public:
virtual void routerStart() = 0;
virtual void control(IPhone* _phone) = 0;
};
class HuaweiRouter : public IRouter
{
public:
virtual void routerStart()
{
cout << "华为路由器开机" << endl;
}
virtual void control(IPhone* _phone)
{
cout << "华为路由器被" << _phone->phoneName()<<"手机控制"<< endl;
}
};
//客户
class Client
{
public:
void getWorking()
{
IPhone* phone = new HuaweiPhone;
phone->phoneStart();
IRouter* router = new HuaweiRouter;
router->routerStart();
router->control(phone);
}
};
int main()
{
Client c;
c.getWorking();
system("pause");
return 0;
}
2.扩展出小米手机和路由器的类+加入抽象工厂模式
#include
#include
using namespace std;
//手机基类
class IPhone
{
public:
virtual void phoneStart() = 0;
virtual string phoneName() = 0;
};
class HuaweiPhone : public IPhone
{
public:
virtual void phoneStart()
{
cout << "华为手机开机" << endl;
}
virtual string phoneName()
{
return string("华为");
}
};
class XiaomiPhone : public IPhone
{
public:
virtual void phoneStart()
{
cout << "小米手机开机" << endl;
}
virtual string phoneName()
{
return string("小米");
}
};
//路由器基类
class IRouter
{
public:
virtual void routerStart() = 0;
virtual void control(IPhone* _phone) = 0;
};
class HuaweiRouter : public IRouter
{
public:
virtual void routerStart()
{
cout << "华为路由器开机" << endl;
}
virtual void control(IPhone* _phone)
{
cout << "华为路由器被" << _phone->phoneName()<<"手机控制"<< endl;
}
};
class XiaomiRouter : public IRouter
{
public:
virtual void routerStart()
{
cout << "小米路由器开机" << endl;
}
virtual void control(IPhone* _phone)
{
cout << "小米路由器被" << _phone->phoneName() << "手机控制" << endl;
}
};
/******抽象工厂介入 start******/
class IAbstractFactor
{
public:
virtual IPhone* creatPhone() = 0;
virtual IRouter* creatRouter() = 0;
};
//华为工厂
class HuaweiFactor : public IAbstractFactor
{
public:
virtual IPhone* creatPhone() { return new HuaweiPhone; }
virtual IRouter* creatRouter(){ return new HuaweiRouter; }
};
//小米工厂
class XiaomiFactor : public IAbstractFactor
{
public:
virtual IPhone* creatPhone() { return new XiaomiPhone; }
virtual IRouter* creatRouter(){ return new XiaomiRouter; }
};
/******抽象工厂介入 end******/
//客户
class Client
{
IAbstractFactor* factor;
public:
Client(IAbstractFactor* _factor) : factor(_factor){}
void getWorking()
{
IPhone* phone = factor->creatPhone();
phone->phoneStart();
IRouter* router = factor->creatRouter();
router->routerStart();
router->control(phone);
}
};
int main()
{
Client c(new HuaweiFactor);
c.getWorking();
Client c1(new XiaomiFactor);
c1.getWorking();
system("pause");
return 0;
}
一个工厂(ConcreteFactor1)生产一系列相互依赖的对象(ProductA1 ProductB1)。
多系列
对象构建”的需求变化,则没有必要使用Abstract Factory模式,这时候使用简单的工厂完全可以。