Abstract Factory Design Pattern in C++: Before and after

Read full article

Trying to maintain portability across multiple “platforms” routinely requires lots of preprocessor “case” statements. The Factory pattern suggests defining a creation services interface in a Factory base class, and implementing each “platform” in a separate Factory derived class.

Before

The client creates “product” objects directly, and must embed all possible platform permutations in nasty looking code.

#define MOTIF

class Widget {
public:
   virtual void draw() = 0;
};

class MotifButton : public Widget {
public:
   void draw() { cout << "MotifButton\n"; }
};
class MotifMenu : public Widget {
public:
   void draw() { cout << "MotifMenu\n"; }
};

class WindowsButton : public Widget {
public:
   void draw() { cout << "WindowsButton\n"; }
};
class WindowsMenu : public Widget {
public:
   void draw() { cout << "WindowsMenu\n"; }
};

void display_window_one() {
#ifdef MOTIF
   Widget* w[] = { new MotifButton,
                   new MotifMenu };
#else // WINDOWS
   Widget* w[] = { new WindowsButton,
                   new WindowsMenu };
#endif
   w[0]->draw();  w[1]->draw();
}

void display_window_two() {
#ifdef MOTIF
   Widget* w[] = { new MotifMenu,
                   new MotifButton };
#else // WINDOWS
   Widget* w[] = { new WindowsMenu,
                   new WindowsButton };
#endif
   w[0]->draw();  w[1]->draw();
}

int main() {
#ifdef MOTIF
   Widget* w = new MotifButton;
#else // WINDOWS
   Widget* w = new WindowsButton;
#endif
   w->draw();
   display_window_one();
   display_window_two();
}
MotifButton MotifButton MotifMenu MotifMenu MotifButton

After

The client: creates a platform- specific “factory” object, is careful to eschew use of “new”, and delegates all creation requests to the factory.

#define WINDOWS

class Widget {
public:
   virtual void draw() = 0;
};

class MotifButton : public Widget {
public:
   void draw() { cout << "MotifButton\n"; }
};
class MotifMenu : public Widget {
public:
   void draw() { cout << "MotifMenu\n"; }
};

class WindowsButton : public Widget {
public:
   void draw() { cout << "WindowsButton\n"; }
};
class WindowsMenu : public Widget {
public:
   void draw() { cout << "WindowsMenu\n"; }
};

class Factory {
public:
   virtual Widget* create_button() = 0;
   virtual Widget* create_menu() = 0;
};

class MotifFactory : public Factory {
public:
   Widget* create_button() {
      return new MotifButton; }
   Widget* create_menu()   {
      return new MotifMenu; }
};

class WindowsFactory : public Factory {
public:
   Widget* create_button() {
      return new WindowsButton; }
   Widget* create_menu()   {
      return new WindowsMenu; }
};

Factory* factory;

void display_window_one() {
   Widget* w[] = { factory->create_button(),
                   factory->create_menu() };
   w[0]->draw();  w[1]->draw();
}

void display_window_two() {
   Widget* w[] = { factory->create_menu(),
                   factory->create_button() };
   w[0]->draw();  w[1]->draw();
}

int main() {
#ifdef MOTIF
   factory = new MotifFactory;
#else // WINDOWS
   factory = new WindowsFactory;
#endif

   Widget* w = factory->create_button();
   w->draw();
   display_window_one();
   display_window_two();
}
WindowsButton WindowsButton WindowsMenu WindowsMenu WindowsButton

Design Patterns

contents