Я хотел бы реализовать шаблон Abstract Factory, но также хотел бы быть одиночкой.
class WindowFactory {
protected:
virtual Scrollbar* createScrollbar() = 0;
};
class MacWindowFactory: public WindowFactory {
virtual Scrollbar* createScrollbar() {
//return a instance
}
;
};
class LinuxWindowFactory: public WindowFactory {
virtual ScrollBar* createScrollbar() {
//return a instance
}
;
};
Может ли кто-нибудь помочь мне с примером кода создания этого абстрактного фабричного синглтона?
Заранее спасибо.
Мне удалось придумать более элегантное решение (без проверки ошибок на данный момент). Пожалуйста, дайте мне знать ваши мысли
#include<iostream>
#include<map>
class AbstractFactory
{
private:
typedef std::map< std::string, AbstractFactory* > ClientMap;
static ClientMap s_clientMap;
public:
void virtual createScrollbar() = 0;
void virtual createWindow() = 0;
static AbstractFactory* createInstance( std::string client );
protected:
void Register( std::string, AbstractFactory* );
};
AbstractFactory::ClientMap AbstractFactory::s_clientMap;
class LinuxFactory: public AbstractFactory
{
public:
void createScrollbar()
{
std::cout<<"Scrollbar for Linux"<<std::endl;
}
void createWindow()
{
std::cout<<"WIndow for Linux"<<std::endl;
}
private:
LinuxFactory()
{
Register( "Linux", this );
}
LinuxFactory( const LinuxFactory& );
static LinuxFactory s_LinuxFactory;
};
LinuxFactory LinuxFactory::s_LinuxFactory;
class MacFactory: public AbstractFactory
{
public:
void createScrollbar()
{
std::cout<<"Scrollbar for Mac"<<std::endl;
}
void createWindow()
{
std::cout<<"WIndow for Mac"<<std::endl;
}
private:
MacFactory()
{
Register( "Mac", this );
}
MacFactory( const MacFactory& );
static MacFactory s_MacFactory;
};
MacFactory MacFactory::s_MacFactory;
void AbstractFactory::Register( std::string clientName, AbstractFactory* factory )
{
s_clientMap.insert( ClientMap::value_type( clientName, factory ) );
}
AbstractFactory* AbstractFactory::createInstance( std::string client )
{
return s_clientMap.find( client )->second;
}
int main()
{
AbstractFactory *factory = AbstractFactory::createInstance( "Linux" );
factory->createScrollbar();
factory->createWindow();
}
Если вам нужна действительно динамическая абстрактная фабрика, вам нужно как-то настроить ее во время выполнения. Вы можете сделать это, имея функцию выбора требуемой фабрики с подходящей функцией, которая просто устанавливает фактический синглтон. В реальном приложении у вас, вероятно, была бы какая-то функция регистрации, где вы можете регистрировать функции, получая экземпляр для фабрики (фабричные функции фабрики). В приведенном ниже примере я использовал простую настройку, в которой доступные фабрики известны во время компиляции.
#include <memory>
#include <stdexcept>
#include <string>
class Scrollbar;
class WindowFactory {
public:
static void setFactory(std::string const&);
static Scrollbar* createScrollbar();
virtual ~WindowFactory() {}
private:
virtual Scrollbar* doCreateScrollbar() = 0;
};
class MacWindowFactory
: public WindowFactory {
friend void WindowFactory::setFactory(std::string const&);
virtual Scrollbar* doCreateScrollbar() {
return 0;
}
};
class LinuxWindowFactory
: public WindowFactory {
friend void WindowFactory::setFactory(std::string const&);
virtual Scrollbar* doCreateScrollbar() {
return 0;
}
};
// in WindowFactory.cpp
static std::auto_ptr<WindowFactory>& getPointer()
{
static std::auto_ptr<WindowFactory> pointer;
return pointer;
}
Scrollbar* WindowFactory::createScrollbar()
{
return getPointer().get()
? getPointer()->doCreateScrollbar()
: throw std::runtime_error("WindowFactory not set");
}
void WindowFactory::setFactory(std::string const& what)
{
if (what == "Mac") {
getPointer() = std::auto_ptr<WindowFactory>(new MacWindowFactory());
}
else if (what == "Linux") {
getPointer() = std::auto_ptr<WindowFactory>(new LinuxWindowFactory());
}
else {
throw std::runtime_error("unknown factory: '" + what + "'");
}
}
namespace WindowFactory {
Scrollbar* createScrollbar() {
#ifdef TARGET_OS_MAC
...
#elif __linux__
...
#endif
}
};
Это то, как я бы это сделал.