Factory method implementation - C++


Question

I have the following code for "factory" design pattern implementation.

class Pen{
public:
     virtual void Draw() = 0;
};

class RedPen : public Pen{
public:
     virtual void Draw(){
         cout << "Drawing with red pen" << endl;
     }
};

class BluePen : public Pen{
public:
     virtual void Draw(){
         cout << "Drawing with blue pen" << endl;
     }
};

auto_ptr<Pen> createPen(const std::string color){
     if(color == "red")
         return auto_ptr<Pen>(new RedPen);
     else if(color == "blue")
         return auto_ptr<Pen>(new BluePen);
}

But I heard that it can be done in a better way using "C++ templates". Can anyone help how it is done and how template approach is better than this?

Any thoughts

1
3
10/31/2012 4:02:18 PM

Accepted Answer

In the example you posted, neither a factory or a template approach makes sense to me. My solution involves a data member in the Pen class.

class Pen {
public:
    Pen() : m_color(0,0,0,0) /* the default colour is black */
    {            
    }

    Pen(const Color& c) : m_color(c)
    {
    }

    Pen(const Pen& other) : m_color(other.color())
    {
    }

    virtual void Draw()
    {
        cout << "Drawing with a pen of color " << m_color.hex();
    }
    void setColor(const Color& c) { m_color = c; }
    const Color& color() const { return m_color; }
private:
    Color m_color;
};

class Color {
public:
    Color(int r, int g, int b, int a = 0) :
        m_red(r), m_green(g), m_blue(other.blue()), m_alpha(a)  
    {
    }

    Color(const Color& other) : 
        m_red(other.red()), m_green(other.green()), 
        m_blue(other.blue()), m_alpha(other.alpha())
    {
    }

    int red() const { return m_red; }
    int green() const  { return m_green; }
    int blue() const { return m_blue; }
    int alpha() const { return m_alpha; }

    std::string hex() const
    {
        std::ostringstream os;
        char buf[3];
        os << "#";

        sprintf(buf, "%2X", red());
        os << buf;

        sprintf(buf, "%2X", green());
        os << buf;

        sprintf(buf, "%2X", blue());
        os << buf;

        sprintf(buf, "%2X", alpha());
        os << buf;

        return os.str();
    }

private:
    int m_red;
    int m_green;
    int m_blue;
    int m_alpha;
}

Of course, the color class would have to be adjusted to the drawing API you use -- and perhaps be way more advanced than this one (different color spaces, etc).

Why not templates?

The reason it does not make sense to use templates, is that (presumably) the only difference between the different drawing operations is the color variable. So, by using templates (or manually declaring different classes, as you did), you will duplicate similar code. This will make your program large, and slow it down.

So, the draw function should either take the color as an argument, or (as in my example) have the color as a class data member.

4
1/4/2009 11:34:37 AM

Another way is to dynamically register a creator function to a dynamical Factory object.

BluePen *create_BluePen() { return new BluePen; }
static bool BluePen_creator_registered = 
                       Factory::instance()->registerCreator("BluePen", 
                                                            create_BluePen);

One interesting effect in doing like this is that the static bool variable BluePen-creator-registered will be set prior main() starts thus making the registering automated.

These lines are sometimes made through ordinary macros, ie as

#define METAIMPL( _name ) \
_name *create_ ## _name() { return new _name; } \
static bool _name ## _creator_registered = \
                        Factory::instance()->registerCreator(# _name, \
                                                             create_ ## _name)

...and used close to the constructor

METAIMPL( BluePen ); // auto registers to the Factory

BluePen::BluePen() : Pen() {
   // something
}

Then the Factory's task will be to store and lookup these creator functions. I leave the rest as the exercise ;) ie the use of a METADECL macro

If you want more info, see here under chapter 4.1 Meta Information which also includes a method for expanding to include possibilities for inspector features

I learnt this from using ET++ that was a project to port old MacApp to C++ and X11. In the effort of it Eric Gamma etc started to think about Design Patterns

And...(May 7 2011) Finally came around to push an example to github
https://github.com/epatel/cpp-factory


Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon