Creational

Abstract Factory

Purpose

Provides an interface for creating families of related widgets without having to specify their concrete classes.

Note: Abstract Factory and Prototype are competing patterns.

UML

Behavior

Given a criteria, the appropriate concrete factory is created at run-time. This single instance is then used to create its own family of widgets. To create and use a different family of widgets, a different concrete factory is created.

Example

The following example uses the Abstract Factory pattern to allow an application to be dynamically configured with a UI skin. The UIFactory class is the Abstract Factory that defines an interface for creating UI widgets. Classes derived from UIFactory specialize the public interface operations to create these widgets. Whether we wanted to use a Windows UI widgets or Java UI widgets, all we have to do is create the appropriate concrete factory and then use the same interface to create the widgets.

Usage

#include <iostream>
#include "button.h"
#include "window.h"

/* FACTORY CLASSES */

/* AbstractFactory: Declares an interface for creating product objects.
In this example, the abstract factory declares an interface for creating user interface widgets, such as buttons and windows */

class UIFactory
{
// Ctor/Dtor
public:
    ~UIFactory(){}

// Public interface
public:
    virtual CButton* CreateButton() = 0;
    virtual CWindow* CreateWindow() = 0;
};

/* ConcreteFactory: Implements AbstractFactory operations to create concrete product objects. 
In this example, WindowsFactory is a ConcreteFactory that implements UIFactory operations by creating Windows-specific UI objects */
class WindowsUIFactory : public UIFactory
{
public:
    CButton* CreateButton() 
    {
        return new CWindowsButton;
    }

    CWindow* CreateWindow()
    {
        return new CWindowsWindow;
    }
};

/* ConcreteFactory: Implements AbstractFactory operations to create concrete product objects. 
In this example, JavaFactory is a ConcreteFactory that implements UIFactory operations by creating Java-specific UI objects */

class JavaUIFactory : public UIFactory
{
public:
    CButton* CreateButton() 
    {
        return new CJavaButton;
    }

    CWindow* CreateWindow()
    {
        return new CJavaWindow;
    }
};

/* PRODUCT CLASSES */

/* AbstractProduct: Declares an interface for a creating a product, (a Button)
In this example, the AbstractProduct declares an interface for a specific widget, a button widget */


class CButton
{
// Ctor/Dtor
public:
    virtual ~CButton() {}

    // public Interface
    public:
    virtual void Click() = 0;
    virtual void Enable( bool bEnabled ) = 0;

    // ... Other methods for interfacing with a button
};

/* ConcreteProduct: Implements the Abstract product interface. It also defines a widget to be created by the its concrete factory, WindowsUIFactory*/
class CWindowsButton : public CButton
{
public:
    void Click()                 { std::cout << "CWindowsButton::Click" << std::endl;}
    void Enable( bool bEnabled ) { std::cout << "CWindowsButton::Enable" << std::endl;}

};

/* ConcreteProduct: Implements the Abstract product interface. It also defines a widget to be created by the its concrete factory, JavaUIFactory*/
class CJavaButton : public CButton
{
public:
    void Click()                 { std::cout << "CJavaButton::Click" << std::endl;}
    void Enable( bool bEnabled ) { std::cout << "CJavaButton::Enable" << std::endl;}

};

/* PRODUCT CLASSES */

/* AbstractProduct: Declares an interface for a creating a product. 
In this example, the AbstractProduct declares an interface for a specific widget, a window widget */

class CWindow
{
// Ctor/Dtor
public:
    virtual ~CWindow() {}

// public Interface
public:
    virtual void SetStyle( int nStyle ) = 0;
    virtual void SetSize( int nLength, int nHeight) = 0;

    // ... Other methods for interfacing with a window
};

/* ConcreteProduct: Implements the Abstract product interface. It also defines a widget to be created by the its concrete factory, WindowsUIFactory */
class CWindowsWindow : public CWindow
{
public:
    void SetStyle( int nStyle )
    { std::cout << "CWindowsWindow::SetStyle" << std::endl;}

    void SetSize( int nLength, int nHeight)
    { std::cout << "CWindowsWindow::SetSize" << std::endl;}
};

/* ConcreteProduct: Implements the Abstract product interface. It also defines a widget to be created by the its concrete factory, JavaUIFactory */
class CJavaWindow : public CWindow
{
public:
    void SetStyle( int nStyle )
    { std::cout << "CJavaWindow::SetStyle" << std::endl;}

    void SetSize( int nLength, int nHeight)
    { std::cout << "CJavaWindow::SetSize" << std::endl;}
};

#include "stdafx.h"
#include <memory>
#include "AbstractFactory.h"

// Helpers
void CreateNewLookAndFeel( const std::auto_ptr<UIFactory>& spFactory );
int GetUserUIChoice();

int main(int argc, char* argv[])
{
    std::auto_ptr<UIFactory> spFactory;
    switch( GetUserUIChoice() )
    {
        case 10: // Windows UI, please
            spFactory = std::auto_ptr<UIFactory>( new WindowsUIFactory );
            CreateNewLookAndFeel( spFactory );
            break;
        case 11: // Java UI, please
            spFactory = std::auto_ptr<UIFactory>(new JavaUIFactory );
            CreateNewLookAndFeel( spFactory );
    } 
    return 0;
}

/* Simulate user interaction by returning an integer denoting user choice for a UI */
int GetUserUIChoice()
{
    return 10; // Windows UI
}

/* CreateNewLookAndFeel simulates creating and adding widgets to the screen. Note that the actual functions called depend on the dynamic type of the pointer wrapped by spFactory. For example (using raw pointer):
    UIFactory *pWUIFactory = new WindowsUIFactory;
    CreateNewLookAndFeel( pWUIFactory );

CreateNewLookAndFeel will create Windows look and feel widgets since the dynamic type is WindowsUIFactory.

auto_ptr<>: Recall that passing an auto_ptr by value to a function implies transfer of ownership to the function. To prevent transfer of ownership pass auto_ptr<> using const &. Never pass auto_ptr<> by reference only */

void CreateNewLookAndFeel( const std::auto_ptr<UIFactory>& spFactory )
{
    /* Create a window. The window can then be added to screen */
    CWindow *pWin = spFactory->CreateWindow();
    pWin->SetSize( 10, 20);
    pWin->SetStyle( 0 );


    /* Create a button. Button can then be added to a window*/
    CButton* pBtn = spFactory->CreateButton();
    pBtn->Enable( true );
}

 
Notes