您的位置:首页 > 编程语言 > C语言/C++

C++:浅谈工厂模式与抽象工厂模式

2016-04-24 13:53 621 查看

C++:浅谈工厂模式与抽象工厂模式

标签: C++ 工厂模式 抽象工厂模式

by 小威威

之前写过一篇谈模式的文章:单例模式

接下来我将浅显的谈谈工厂模式抽象工厂模式

工厂模式抽象工厂模式虽有差异,但实现的目的可以看成一致的:

They offers the interface for creating a family of related objects, without explicitly specifying their classes.

它们给一系列有联系的对象提供了创建的接口,而不用显式地明确类名。

接下来我来通过两张图,进一步了解这两种模式的原理与差异。

1.工厂模式



这张图就是工厂模式的原理。希望读者能以实际生活中的工厂来了解这张图。

首先,我们可以把ProductFactory想象成生产某种产品(抽象类产品)的某类工厂(抽象类工厂),这个抽象类工厂演变出许多实例化对象,也就是实际的工厂:ConcreteProductFactoryA,ConcreteProductFactoryB。这两个实例化工厂生产的内容与抽象工厂定义的内容一致,即包含一个抽象类product。

然后,如上文所讲,Product是某种产品(抽象类产品),它也能演变出许多实例化对象:ConcreteProductA,ConcreteProductB。也就是上面的实例化工厂都能生产A、B两种产品。

举个例子:

现在有生产水果罐头的工厂(抽象类工厂):工厂1(工厂实例化对象),工厂2(工厂实例化对象)。这两个工厂都生产着水果罐头(抽象类产品) : 水蜜桃罐头(产品实例化对象),哈密瓜罐头(产品实例化对象),苹果罐头(产品实例化对象)。

这样讲就形象多了吧。

2.抽象工厂模式



这张图就是抽象工厂模式的原理。希望读者能以实际生活中的工厂来了解这张图。

首先,我们可以把AbstractFactory看作是一类能够生产多种产品的工厂(抽象类工厂),这个工厂演变出许多实例化对象,也就是ConcreteFactory1(工厂实例化对象)和ConcretrFactory2(工厂实例化对象)。这两个实例化工厂生产的内容与抽象工厂定义的内容一致,即为AbstractProductA(抽象类产品),AbstractProductB(抽象类产品)。

然后AbstractProductA,AbstractProductB也能分别演变出许多实例化对象:如AbstractProductA可演变成ProductA1(产品实例化对象),ProductA2(产品实例化对象),AbstractProductB可演变成ProductB1(产品实例化对象), ProductB2(产品实例化对象)。

举个例子:

现在有生产水果罐头和肉类罐头的工厂(抽象类工厂):工厂1(工厂实例化对象),工厂2(工厂实例化对象)。这两个工厂都生产着水果罐头(抽象类产品),肉类罐头(抽象类产品)。水果罐头的种类有:水蜜桃罐头(产品实例化对象),苹果罐头(产品实例化对象),肉类罐头的种类有:牛肉罐头(产品实例化对象),猪肉罐头(产品实例化对象)。

文章推荐:抽象工厂模式C++实现

3.两种模式的差异

工厂模式

只有一个抽象工厂,能生成许多实例化工厂。

只有一个抽象产品,能生成许多实例化产品。

也就是说,工厂模式下,抽象工厂内只有一种抽象类产品,即这类工厂只能生产一类产品。

抽象工厂模式

只有一个抽象工厂,能生成许多实例化工厂。

拥有多个抽象类产品,每个抽象类产品能生成许多实例化产品。

也就是说,抽象工厂模式下,抽象工厂内有多种抽象类产品,即这类工厂能生产多类产品。

由此可以发现他们之间的差异。

4.工厂模式的优缺点

当接触到这个模式的时候,必然会有人问:“这种模式有什么优点?我为什么要用这种模式?”

当然,模式的使用也要依情况而定。有时候方便有时候也会带来麻烦。

如我们现在我们定义一个派生类作为原来的类的补充,即是要用派生类来替换基类。这种情况下,显然工厂模式修改代码较为方便。原因是:工厂模式下,具体调用者不负责创建对象,并且创建对象返回的是接口类型,因此当要修改时,只需修改工厂,而无需全盘修改。但是小程序就不一样了,有很多地方需要修改。

但是,如果是要增加类的方法,那么工厂模式便会非常复杂。首先他要在抽象类中补充方法,其次还要在这个抽象类的所有派生类中补充方法。这是非常麻烦的,尤其是工程较大的时候。小程序就不一样了,此时它只需直接在类中增加方法即可。

5.例题

Assignment

This time we are going to use Abstract Factory to finish this problem.

We have a multi-platform support Graphic programming task that need some widgets of different platform tools.

For example, in Microsoft Windows, we use MFC to produce window widgets.

We are going to design how to use Abstract Factory to finish this job.

Please analyze the main function and then download the executable binary program to meet you result.

Client.cpp已给出:

#include <iostream>
#include <string>

#include "Factory.hpp"
#include "Product.hpp"

int main() {
UIFactory* ui = 0;

int choose;

std::cin >> choose;

switch (choose) {
case 0:
ui = new MFCUIFactory();
break;
case 1:
ui = new GtkUIFactory();
break;
case 2:
default:
ui = new QtUIFactory();
}

/* Use the factory to build interface. */
Window* toolbox = ui->getToolboxWindow();
Window* layers = ui->getLayersWindow();
Window* main = ui->getMainWindow();

/* See what have we recieved. */
std::cout << toolbox->getToolkit() << ":" << toolbox->getType() << std::endl;
std::cout << layers->getToolkit() << ":" << layers->getType() << std::endl;
std::cout << main->getToolkit() << ":" << main->getType() << std::endl;

ui->deleteWindow(toolbox);
ui->deleteWindow(layers);
ui->deleteWindow(main);

delete ui;
}


分析main函数可知:

(1)UIFactory是一个抽象工厂,MFCUIFactory,GtkUIFactory, QtUIFactory都是这个抽象工厂的实例化对象。

(2)Window是一个抽象产品,ToolboxWindow, LayersWindow, MainWindow都是该抽象产品的实例化对象。

因为这里有三个工厂,所以每一种产品都会有三种类型,即:

ToolboxWindow有MFC,Gtk,Qt工厂制造;

LayersWindow有MFC,Gtk,Qt工厂制造;

MainWindow有MFC,Gtk,Qt工厂制造。

换句话说,Window这个产品抽象类有3*3=9个实例化对象。

理清层次后,再根据Client.cpp的调用者将方法进行分类。

Factory.cpp 如下:

# ifndef FACTORY_H_
# define FACTORY_H_
# include "Product.hpp"
class UIFactory {
public:
virtual Window* getToolboxWindow() = 0;
virtual Window* getLayersWindow() = 0;
virtual Window* getMainWindow() = 0;
virtual void deleteWindow(Window* pArr) { delete pArr; }
};
class MFCUIFactory : public UIFactory {
Window* getToolboxWindow() {
return new MFC_ToolboxWindow();
}
Window* getLayersWindow() {
return new MFC_LayersWindow();
}
Window* getMainWindow() {
return new MFC_MainWindow();
}
};
class GtkUIFactory : public UIFactory {
Window* getToolboxWindow() {
return new Gtk_ToolboxWindow();
}
Window* getLayersWindow() {
return new Gtk_LayersWindow();
}
Window* getMainWindow() {
return new Gtk_MainWindow();
}
};
class QtUIFactory : public UIFactory {
Window* getToolboxWindow() {
return new Qt_ToolboxWindow();
}
Window* getLayersWindow() {
return new Qt_LayersWindow();
}
Window* getMainWindow() {
return new Qt_MainWindow();
}
};
#endif


Product.hpp 如下:

# ifndef PRODUCT_H_
# define PRODUCT_H_
# include <string>
class Window {
public:
virtual std::string getToolkit() = 0;
virtual std::string getType() = 0;
};
class MFC_ToolboxWindow : public Window {
public:
std::string getToolkit() { return "MFC"; }
std::string getType() { return "ToolboxWindow"; }
};
class Gtk_ToolboxWindow : public Window {
public:
std::string getToolkit() { return "Gtk"; }
std::string getType() { return "ToolboxWindow"; }
};
class Qt_ToolboxWindow : public Window {
public:
std::string getToolkit() { return "Qt"; }
std::string getType() { return "ToolboxWindow"; }
};
class MFC_LayersWindow : public Window {
public:
std::string getToolkit() { return "MFC"; }
std::string getType() { return "LayersWindow"; }
};
class Gtk_LayersWindow : public Window {
public:
std::string getToolkit() { return "Gtk"; }
std::string getType() { return "LayersWindow"; }
};
class Qt_LayersWindow : public Window {
std::string getToolkit() { return "Qt"; }
std::string getType() { return "LayersWindow"; }
};
class MFC_MainWindow : public Window {
std::string getToolkit() { return "MFC"; }
std::string getType() { return "MainWindow"; }
};
class Gtk_MainWindow : public Window {
std::string getToolkit() { return "Gtk"; }
std::string getType() { return "MainWindow"; }
};
class Qt_MainWindow : public Window {
std::string getToolkit() { return "Qt"; }
std::string getType() { return "MainWindow"; }
};
# endif


输出结果如下:

apple@ubuntu:~/Desktop $ g++ Client.cpp -g
apple@ubuntu:~/Desktop $ ./a.out
0
MFC:ToolboxWindow
MFC:LayersWindow
MFC:MainWindow
apple@ubuntu:~/Desktop $ ./a.out
1
Gtk:ToolboxWindow
Gtk:LayersWindow
Gtk:MainWindow
apple@ubuntu:~/Desktop $ ./a.out
2
Qt:ToolboxWindow
Qt:LayersWindow
Qt:MainWindow


以上内容皆为本人观点,欢迎大家提出批评和指导,我们一起探讨!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: