DESIGN PATTERNS - ABSTRACT FACTORY PATTERN

Posted taxue505

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DESIGN PATTERNS - ABSTRACT FACTORY PATTERN相关的知识,希望对你有一定的参考价值。

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?

Abstract Factory design pattern creates Factory.
Factory design pattern creates Products.

以上是关于DESIGN PATTERNS - ABSTRACT FACTORY PATTERN的主要内容,如果未能解决你的问题,请参考以下文章

Design Principles and Design Patterns

Cloud Design Patterns

Notes on Design Patterns

Design Patterns

Design Patterns

DESIGN PATTERNS - ABSTRACT FACTORY PATTERN