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的主要内容,如果未能解决你的问题,请参考以下文章