工厂模式的意图是将生成对象的代码集中到一个地方,以方便统一管理,最简单的工厂模式是由基类负责生成各种派生类的对象,举个简单例子如下:
class Base {
public:
static Base* create(const string &str);
};
class A : public Base {};
class B : public Base {};
Base* Base::create(const string &str) {
if(str == "A") return new A();
if(str == "B") return new B();
return NULL;
}
这样就可以通过Base::create来创建A或B的对象,注意到create定义成Base的静态函数即可,但是就上面的例子而言,我们依然可以绕过Base::create而创建A或B的对象,即通过A、B的默认构造函数,所以更加严谨的做法可能是将A、B的默认构造函数(拷贝构造函数)定义为private,如下:
class Base {
public:
static Base* create(const string &str);
};
class A : public Base {
A() {}
A(const A&) {}
friend Base* Base::create(const string&);
};
class B : public Base {
B() {}
B(const B&) {}
friend Base* Base::create(const string&);
};
Base* Base::create(const string &str) {
if(str == "A") return new A();
if(str == "B") return new B();
return NULL;
}
注意到A、B的默认构造函数(及拷贝构造函数)被设置成了private,这是为了避免用户通过A、B的构造函数直接生成各自的对象,换言之,强迫用户将生成A、B对象的任务交给Base::create,同时,为了在Base::create中调用A、B的构造函数,需要将Base::create设置为A、B的友元。在实际的使用中,如果我们想增加另外一个派生于Base的类型C,那么只需修改Base::create中的代码即可。
在上面这种最简单的工厂模式中,基类和派生类的耦合还是比较紧的,因为基类的create需要直接操作派生类的构造函数,事实上,我们可以避免基类直接操作派生类的构造函数,这就是所谓的多态工厂。在多态工厂的设计模式中,派生类A和B都有各自的专属工厂,这个专属工厂直接操作A或B的构造函数,基类有个大工厂,这个大工厂通过调用各派生类的专属工厂来生成各派生类的对象,看个简单例子:
class Base {};
class BaseFactory {
static BaseFactory bf;
static map<string, BaseFactory*> factories;
protected:
BaseFactory(){}
BaseFactory(int);
public:
virtual Base* create(){ return NULL; }
static Base* createProduct(const string &str);
};
这是基类以及基类工厂,我们重点关注基类工厂:BaseFactory,这个工厂有一个map结构的数据成员:factories,factories用于保存各派生类的专属工厂,同时,基类工厂还有一个成员函数:createProduct,用于创建各派生类的对象,createProduct的定义如下:
Base* BaseFactory::createProduct(const string &str) {
if(factories.find(str) != factories.end())
return factories[str]->create();
}
所以在createProduct中通过使用actories中保存的各专属工厂来创建派生类对象,str可以是派生类的名字,用于标识创建哪个派生类的对象。再回到BaseFactory中,还有一个
虚成员函数create,这个函数将来会被派生类工厂重新定义,用以创建各派生类的对象,派生类及派生类工厂的定义如下:
class A : public Base {
A() {}
A(const A&) {}
friend class BaseFactory;
class Factory;
friend class Factory;
class Factory : public BaseFactory {
public:
Base* create() { return new A(); }
};
};
派生类工厂是作为派生类的嵌套类进行定义的,且访问属性为private,所以派生类工厂不能在派生类以外被使用,但是由于BaseFactory被定义成了派生类的友元,所以派生类工厂可以被BaseFactory访问,派生类工厂继承于BaseFactory,唯一要做的就是重新定义create(),在create()将完成派生类对象的创建。由于create为虚函数,所以即使使用BaseFactory类型的指针也可以正确访问派生类工厂的create(只要该指针真正指向的是派生类工厂对象)。完整的代码如下:
#include<iostream>
#include<string>
#include<map>
using namespace std;
class Base {};
class BaseFactory {
static BaseFactory bf;
static map<string, BaseFactory*> factories;
protected:
BaseFactory(){}
BaseFactory(int);
public:
virtual Base* create() { return NULL; }
static Base* createProduct(const string &str);
};
map<string, BaseFactory*> BaseFactory::factories;
BaseFactory BaseFactory::bf(1);
Base* BaseFactory::createProduct(const string &str) {
if(factories.find(str) != factories.end())
return factories[str]->create();
}
class A : public Base {
A() {}
A(const A&) {}
friend class BaseFactory;
class Factory;
friend class Factory;
class Factory : public BaseFactory {
public:
Base* create() { return new A(); }
};
};
class B : public Base {
B() {}
B(const B&) {}
friend class BaseFactory;
class Factory;
friend class Factory;
class Factory : public BaseFactory {
public:
Base* create() { return new B(); }
};
};
BaseFactory::BaseFactory(int) {
BaseFactory::factories["A"] = new A::Factory;
BaseFactory::factories["B"] = new B::Factory;
}
int main() {
Base *p = BaseFactory::createProduct("A");
return 0;
}
对上面的代码再做几点解释:
1、基类工厂BaseFactory中有一个自身的static数据成员: bf ,因为bf的定义将发生在main()之前,所以bf存在的意义是调用构造函数以初始化factories,这里bf调用了有参的构造函数;
2、基类工厂BaseFactory中有两个构造函数,一个是无参的默认构造函数,另一个是有int参数的构造函数,前者是用于被派生类工厂调用的(因为创建派生类工厂对象的时候需要调用其基类的默认构造函数),而后者只是为了在定义bf 的时使用,用于初始化factories;
上面的代码只是阐述了多态工厂的基本思想,仍然有很多可以改进的地方,希望大家多提意见,总之,多态工厂就是使用派生类自己的工厂来创建派生类,所以基类就不需要了解太多派生类的细节,只要派生类向基类工厂注册了自己的专属工厂就行。