BogoToBogo
  • Home
  • About
  • Big Data
  • Machine Learning
  • AngularJS
  • Python
  • C++
  • go
  • DevOps
  • Kubernetes
  • Algorithms
  • More...
    • Qt 5
    • Linux
    • FFmpeg
    • Matlab
    • Django 1.8
    • Ruby On Rails
    • HTML5 & CSS

Design Patterns - Abstract Factory Pattern

Patterns.png




Bookmark and Share





bogotobogo.com site search:

Abstract Factory Pattern

Abstract Factory - Provide an interface for creating families of related or dependent objects without specifying their concrete classes.


Abstract Factory pattern lets a class defer instantiation to subclasses. To name the method more descriptively, it can be named as Factory and Product Family Method.

If we want to create a Mac style scroll bar, we can write a code like this:

ScrollBar *sb = new MacScrollBar;
But if we're going to make it work across any platform, we should write a code something similar to this:
ScrollBar *sb = guiFactory->createScrollBar();
Because guiFactory is an instance of MacFactory class, the createScrollBar returns a new instance of Mac style scrollbar. The MacFactory itself is a subclass of GUIFactory which is an abstract class where general interface for widgets.
So, the product objects here, are widgets.
The instance variable guiFactory is initialized as:
GUIFactory *guiFactory = new MacFactory; 


Abstract_Factory_design_pattern

Diagram source: wiki



Here is the example code:

#include <iostream>

class Button
{
public:
	virtual void paint() = 0;
};
 
class WinButton : public Button 
{
public:
	void paint (){
		std::cout << " Window Button \n";
       }
};
 
class MacButton : public Button 
{
public:
	void paint (){
		std::cout << " Mac Button \n";
       }
};

class ScrollBar 
{
public:
	virtual void paint() = 0;
};
 
class WinScrollBar : public ScrollBar 
{
public:
	void paint (){
		std::cout << " Window ScrollBar \n";
       }
};
 
class MacScrollBar : public ScrollBar {
public:

	void paint (){
		std::cout << " Mac ScrollBar \n";
       }
};


class GUIFactory 
{
public:
	virtual Button* createButton () = 0;
	virtual ScrollBar* createScrollBar () = 0;
};
 
class WinFactory : public GUIFactory 
{
public:
	Button* createButton (){
		return new WinButton;
	}
	ScrollBar* createScrollBar (){
		return new WinScrollBar;
	}
};
 
class MacFactory : public GUIFactory 
{
public:
	Button* createButton (){
		return new MacButton;
	}
	ScrollBar* createScrollBar (){
		return new MacScrollBar;
	}
};
 
int main()
{
	GUIFactory* guiFactory;
	Button *btn;
	ScrollBar *sb;

	guiFactory = new MacFactory;
	btn = guiFactory->createButton();
	btn -> paint();
	sb = guiFactory->createScrollBar();
	sb -> paint();

	guiFactory = new WinFactory;
	btn = guiFactory->createButton();
	btn -> paint();
	sb = guiFactory->createScrollBar();
	sb -> paint();

	return 0;
}

The guiFactory object abstracts the process of creating not just MacScrollBar but also scroll bars for any look-and-feel standard. And guiFactory isn't limited to producing scroll bars or buttons. It can manufacture a full range of widgets including menus, text fields etc.

All this is possible because MacFactory is a subclass of GUIFactory, an abstract class that defines a general interface of creating widgets. It includes operations like createScrollBar and createButton for instantiating different kinds of widgets:

class GUIFactory 
{
public:
	virtual Button* createButton () = 0;
	virtual ScrollBar* createScrollBar () = 0;
};

Subclasses of GUIFactory such as MacFactory or WinFactory implement these operations to return widgets such as MacButton or WinScrollBar that implement a particular look and feel.

Which part of the code should be modified if we want to add iPhone look-and-feel?

Not much as you can see from the code below:

#include <iostream>

class Button
{
public:
	virtual void paint() = 0;
};
 
class WinButton : public Button 
{
public:
	void paint (){
		std::cout << " Window Button \n";
       }
};
 
class MacButton : public Button 
{
public:
	void paint (){
		std::cout << " Mac Button \n";
       }
};

class iPhoneButton : public Button 
{
public:
	void paint (){
		std::cout << " iPhone Button \n";
       }
};

class ScrollBar 
{
public:
	virtual void paint() = 0;
};
 
class WinScrollBar : public ScrollBar 
{
public:
	void paint (){
		std::cout << " Window ScrollBar \n";
       }
};
 
class MacScrollBar : public ScrollBar 
{
public:
	void paint (){
		std::cout << " Mac ScrollBar \n";
       }
};

class iPhoneScrollBar : public ScrollBar
{
public:
	void paint (){
		std::cout << " iPhone ScrollBar \n";
       }
};


class GUIFactory 
{
public:
	virtual Button* createButton () = 0;
	virtual ScrollBar* createScrollBar () = 0;
};
 
class WinFactory : public GUIFactory 
{
public:
	Button* createButton (){
		return new WinButton;
	}
	ScrollBar* createScrollBar (){
		return new WinScrollBar;
	}
};
 
class MacFactory : public GUIFactory 
{
public:
	Button* createButton (){
		return new MacButton;
	}
	ScrollBar* createScrollBar (){
		return new MacScrollBar;
	}
};
 
class iPhoneFactory : public GUIFactory 
{
public:
	Button* createButton (){
		return new iPhoneButton;
	}
	ScrollBar* createScrollBar (){
		return new iPhoneScrollBar;
	}
};

int main()
{
	GUIFactory* guiFactory;
	Button *btn;
	ScrollBar *sb;

	guiFactory = new MacFactory;
	btn = guiFactory->createButton();
	btn -> paint();
	sb = guiFactory->createScrollBar();
	sb -> paint();

	guiFactory = new WinFactory;
	btn = guiFactory->createButton();
	btn -> paint();
	sb = guiFactory->createScrollBar();
	sb -> paint();

	guiFactory = new iPhoneFactory;
	btn = guiFactory->createButton();
	btn -> paint();
	sb = guiFactory->createScrollBar();
	sb -> paint();

	return 0;
}

As you see, we didn't have to edit any existing code. All we had to do was just adding the iPhone portion to the existing code!

Output:

 Mac Button
 Mac ScrollBar
 Window Button
 Window ScrollBar
 iPhone Button
 iPhone ScrollBar





2nd Example of Abstract Factory Method

A factory method is simply a normal method call which can return an instance of a class. But they are often used in combination with inheritance such that a derived class overrides the factory method and return an instance of derived class. More often, we implement factories using abstract base classes.

In the following example, we want to render 3D scene using OpenGL, DirectX, oretc. First, we write a base class where derived classes provide the implementation of the pure virtual methods:

#include <iostream>

class Renderer
{
public:
	virtual ~Renderer() {};
	virtual void RenderIt() = 0;
};

class OpenGLRenderer : public Renderer 
{
	void RenderIt() {
		std::cout << "OpenGL render \n";
	}
};

class DirectXRenderer : public Renderer 
{
		void RenderIt() {
		std::cout << "DirectX render \n";
	}
};

#include <string>

class RendererFactory
{
public:
	Renderer *createRenderer(const std::string& type) 
	{
	if(type == "opengl") 
		return new OpenGLRenderer();
	else if(type == "directx") 
		return new DirectXRenderer();
	else return NULL;
	}
};


int main()
{
	RendererFactory *factory = new RendererFactory();
	factory->createRenderer("opengl")->RenderIt();
	factory->createRenderer("directx")->RenderIt();
	return 0;
}

The method createRenderer() cannot return an instance of the specific type Renderer because it's an abstract base class, and cannot be instantiated. It can, however, return instance of derived class. Then, how can we make the derived class? We use the string argument to the methods, Renderer *createRenderer(const std::string& type); , to create an instance of derived class.

We have two concrete class derived from Renderer class:

class OpenGLRenderer : public Renderer {};
class DirectXRenderer : public Renderer {};

Then we provide the implementation of the factory method like this:

Renderer *RendererFactory::createRenderer(const std::string& type)
{
	if(type == "opengl") 
           return new OpenGLRenderer();
	else if(type == "directx") 
           return new DirectXRenderer();
	else return NULL;
}

The design works fine for now. But what should be changed if we want to add another type of renderer? Clearly, we need to modify the RendererFactory class due to its hardcoded knowledge of the available derived classes. Fortunately, in this case, our public API stays, not affected by the addition of renderer. But it means that we cannot add support for new derived class at run time, which means our users cannot add new renderer.

So, let's find more flexible/extensible design.

More to come...




Abstract Factory Pattern vs Factory Method

What's the difference between Abstract Factory Pattern and Factory Method?

  1. Abstract Factory design pattern creates Factory.
  2. Factory design pattern creates Products.





Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization

YouTubeMy YouTube channel

Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong





List of Design Patterns



Introduction

Abstract Factory Pattern

Adapter Pattern

Bridge Pattern

Chain of Responsibility

Command Pattern

Composite Pattern

Decorator Pattern

Delegation

Dependency Injection(DI) and Inversion of Control(IoC)

Façade Pattern

Factory Method

Model View Controller (MVC) Pattern

Observer Pattern

Prototype Pattern

Proxy Pattern

Singleton Pattern

Strategy Pattern

Template Method Pattern

Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong







C++ Tutorials

C++ Home

Algorithms & Data Structures in C++ ...

Application (UI) - using Windows Forms (Visual Studio 2013/2012)

auto_ptr

Binary Tree Example Code

Blackjack with Qt

Boost - shared_ptr, weak_ptr, mpl, lambda, etc.

Boost.Asio (Socket Programming - Asynchronous TCP/IP)...

Classes and Structs

Constructor

C++11(C++0x): rvalue references, move constructor, and lambda, etc.

C++ API Testing

C++ Keywords - const, volatile, etc.

Debugging Crash & Memory Leak

Design Patterns in C++ ...

Dynamic Cast Operator

Eclipse CDT / JNI (Java Native Interface) / MinGW

Embedded Systems Programming I - Introduction

Embedded Systems Programming II - gcc ARM Toolchain and Simple Code on Ubuntu and Fedora

Embedded Systems Programming III - Eclipse CDT Plugin for gcc ARM Toolchain

Exceptions

Friend Functions and Friend Classes

fstream: input & output

Function Overloading

Functors (Function Objects) I - Introduction

Functors (Function Objects) II - Converting function to functor

Functors (Function Objects) - General



Git and GitHub Express...

GTest (Google Unit Test) with Visual Studio 2012

Inheritance & Virtual Inheritance (multiple inheritance)

Libraries - Static, Shared (Dynamic)

Linked List Basics

Linked List Examples

make & CMake

make (gnu)

Memory Allocation

Multi-Threaded Programming - Terminology - Semaphore, Mutex, Priority Inversion etc.

Multi-Threaded Programming II - Native Thread for Win32 (A)

Multi-Threaded Programming II - Native Thread for Win32 (B)

Multi-Threaded Programming II - Native Thread for Win32 (C)

Multi-Threaded Programming II - C++ Thread for Win32

Multi-Threaded Programming III - C/C++ Class Thread for Pthreads

MultiThreading/Parallel Programming - IPC

Multi-Threaded Programming with C++11 Part A (start, join(), detach(), and ownership)

Multi-Threaded Programming with C++11 Part B (Sharing Data - mutex, and race conditions, and deadlock)

Multithread Debugging

Object Returning

Object Slicing and Virtual Table

OpenCV with C++

Operator Overloading I

Operator Overloading II - self assignment

Pass by Value vs. Pass by Reference

Pointers

Pointers II - void pointers & arrays

Pointers III - pointer to function & multi-dimensional arrays

Preprocessor - Macro

Private Inheritance

Python & C++ with SIP

(Pseudo)-random numbers in C++

References for Built-in Types

Socket - Server & Client

Socket - Server & Client 2

Socket - Server & Client 3

Socket - Server & Client with Qt (Asynchronous / Multithreading / ThreadPool etc.)

Stack Unwinding

Standard Template Library (STL) I - Vector & List

Standard Template Library (STL) II - Maps

Standard Template Library (STL) II - unordered_map

Standard Template Library (STL) II - Sets

Standard Template Library (STL) III - Iterators

Standard Template Library (STL) IV - Algorithms

Standard Template Library (STL) V - Function Objects

Static Variables and Static Class Members

String

String II - sstream etc.

Taste of Assembly

Templates

Template Specialization

Template Specialization - Traits

Template Implementation & Compiler (.h or .cpp?)

The this Pointer

Type Cast Operators

Upcasting and Downcasting

Virtual Destructor & boost::shared_ptr

Virtual Functions



Programming Questions and Solutions ↓

Strings and Arrays

Linked List

Recursion

Bit Manipulation

Small Programs (string, memory functions etc.)

Math & Probability

Multithreading

140 Questions by Google



Qt 5 EXPRESS...

Win32 DLL ...

Articles On C++

What's new in C++11...

C++11 Threads EXPRESS...

Go Tutorial

OpenCV...








Contact

BogoToBogo
contactus@bogotobogo.com

Follow Bogotobogo

About Us

contactus@bogotobogo.com

YouTubeMy YouTube channel
Pacific Ave, San Francisco, CA 94115

Pacific Ave, San Francisco, CA 94115

Copyright © 2024, bogotobogo
Design: Web Master