灵光一闪:
抽象工厂模式经常被使用,那么同时也会多次写相同或类似的代码。能不能设计一个通用的工厂类,以避免重复设计工厂类呢?
先回忆一下基础的工厂类设计。
class Button
{
};
class LinuxButton : public Button
{
};
class WindowsButton: public Button
{
};
class AbstractFactory
{
public:
Button* create Button() = 0;
};
class LinuxConcreteFactory : public AbstractFactory
{
public:
Button* createButton()
{
return new LinuxButton ;
}
};
class WindowsConcreteFactory : public AbstractFactory
{
pulbic:
Base *createBase()
{
return new WindowsButton;
}
};
以上是一个基本的抽象工厂类。这套代码会根据不同的操作实现不同的控件,比如运行在linux下,那么会要产生一个Linux格式的Button,运行在Windows下,那么会产生Windows的Button。很多用过工厂类的猿们应该都有写过这样的工厂。但是这样的工厂有很大的问题:
- 有新产品类时,要修改AbstractFactory的接口,同时要改变所有具体工厂去实现新的创建对象函数。比如,现在要加一个Label的控件,那么会有Label、LinuxLabel和WindowsLabel类。这时就要去修改AbstractFactory的接口,然后所有实现类都要去实现新的函数。
- 要记住每个类创建对象的对应函数,当然,名字取得得当,这不是问题,就像上面的例子一样,对于类Button,创建一个createButton的函数。
- 当要使用这个工厂创建对象的类非常多时,这时工厂的接口就非常大。
- 当具体工厂的个数比较多时,这样实现具体工厂就更加麻烦。比如,这时要加上Mac系统的控件,此时就得去新建一个MacConcreteFactory的类,并去继承AbstractFactory类,然后实现所以函数。
那么有没有比较简便点的方法呢?
=============================================================================
下面给出一个《C++ API设计》这本书的一个工厂类的设计。
Button* createLinuxButton()
{
return new LinuxButton;
}
Button *createWindowsButton()
{
return new WindowsButton;
}
class ButtonFactoryEx
{
public:
void registerClass(const string &name, Button* (*callback)())
{
cm[name] = callback;
}
Button* create(const string &name)
{
CreateMap::iterator it = cm.find(name);
if (it != cm.end())
{
return (*(it->second))();
}
else
{
return NULL;
}
}
// ...省略一些其他不用介绍的函数,可以参考《C++ API设计》
private:
typedef Button* (*CreateCallback)();
typedef map<string, CreateCallback> CreateMaps;
CreateMaps cm;
};