4

I would like to implement a Abstract Factory pattern but also would like to be a singleton.

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
    }
    ;
};

Can someone help me with some sample code of making this Abstract Factory Singleton ?

Thanks in advance.

3 Answers 3

8

I managed to come up with more elegant solution ( No error checking as of now ). Kindly let me know your thoughts

#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();
}
Sign up to request clarification or add additional context in comments.

Comments

1

If you need an actually dynamic abstract factory, you'd need to somehow set it up at run-time. You can do this by having a function selecting the desired factory with a suitable function which just sets up the actual singleton. In a real application you would probably have some sort of registration function where you can register functions getting an instance for the factory (factory factory functions). In the example below I used a simple set up where the available factories are known at compile time.

#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 + "'");
    }
}

1 Comment

This is just absolutely brilliant ! Thanks.
0
namespace WindowFactory {
      Scrollbar* createScrollbar() {
        #ifdef TARGET_OS_MAC 
         ...
        #elif __linux__ 
         ...
        #endif
      }
};

It's how I would've done it.

5 Comments

Thanks. In this specific example yes. But I would like to avoid the use of macros as much as possible and stick to object oriented principles as much as possible.
He's not using macros, at least not conceptually. He's merely checking for the compilation platform, which uses the macro mechanism, but doesn't actually have any of the problems that usually make macros a bad choice. It's just that no compiler offers such checks in any other way.
A sidenote: for stuff that returns void, or generally doesn't cause a compiler error when no code branch is compiled, I also add a final "#else #error Missing implementation #endif" to make sure it gets noticed.
Do check the solution I have posted. Thanks
I agree with this general style, but I'd take it one step further and put them in separate source (and possibly header) files and only compile/include only the ones specific to my platform.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.