目录
已同步到公众号:
一、抽象工厂概念及结构流程图:
抽象工厂模式是一种创建型模式,用于提供一个接口以创建一系列相关或相互依赖的对象,而无需指定它们的具体类。下面是抽象工厂模式的简单流程图:
+-------------------+ +----------------+
| Client | | AbstractFactory|
+-------------------+ +--------+-------+
| |
| |
| |
| |
v v
+-------------------+ +--------+-------+
| AbstractProductA| | AbstractProductB|
+-------------------+ +--------+-------+
^ ^
| |
| |
| |
+-------------------+ +--------+-------+
| ConcreteProductA1| | ConcreteProductB1|
+-------------------+ +--------+-------+
^ ^
| |
| |
| |
+-------------------+ +--------+-------+
| ConcreteProductA2| | ConcreteProductB2|
+-------------------+ +-----------------+
在这个流程图中,Client
类通过 AbstractFactory
接口创建 AbstractProductA
和 AbstractProductB
对象。AbstractFactory
接口定义了创建产品的方法,而具体的工厂类实现了这些方法。每个具体的工厂类可以创建一系列相关的产品,比如 ConcreteProductA1
和 ConcreteProductB1
,或者 ConcreteProductA2
和 ConcreteProductB2
。
这个流程图展示了抽象工厂模式的基本结构,通过抽象工厂和抽象产品的定义,可以方便地扩展新的产品系列,并且客户端代码可以方便地切换不同的产品系列。
上图过于抽象,再上一个结构图看看:
抽象工厂模式的结构图如下所示:
Client
|
| 使用
V
AbstractFactory ------------------- AbstractProductA
| |
| 创建 |
V V
ConcreteFactory1 - 创建-> ConcreteProductA1
| |
| 创建 |
V V
ConcreteFactory2 - 创建-> ConcreteProductA2
|
| 创建
V
AbstractProductB
|
| 创建
V
ConcreteProductB1
在这个结构图中,Client
是客户端代码,它使用抽象工厂来创建一系列的产品。AbstractFactory
是抽象工厂接口,定义了创建产品的方法。ConcreteFactory1
和 ConcreteFactory2
是具体的工厂类,实现了抽象工厂接口,分别用来创建一系列相关的产品。AbstractProductA
和 AbstractProductB
是抽象产品接口,定义了产品的通用方法。ConcreteProductA1
、ConcreteProductA2
和 ConcreteProductB1
是具体的产品类,实现了抽象产品接口,分别代表不同的产品。
整个抽象工厂模式的核心在于,客户端通过抽象工厂来创建产品,而具体的产品创建细节被封装在具体的工厂类中,客户端不需要关心具体产品的创建过程。同时,抽象工厂模式保证了产品族之间的一致性,使得客户端可以一次性获取一整套相关的产品。
再优化一下结构图:
下面是优化后的抽象工厂模式的结构图:
Client
|
| 使用
V
[AbstractFactory]<>--------->[ConcreteFactory1]
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
V V V
[AbstractProductA] [ConcreteProductA1]
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
V V V
[ConcreteProductA2] [ConcreteProductB1]
在这个优化后的结构图中,方括号表示抽象的部分,箭头表示依赖关系。Client
通过抽象工厂来创建产品,而具体的产品创建细节被封装在具体的工厂类和具体的产品类中。这种结构图更加清晰地展示了抽象工厂模式的组成部分和它们之间的关系。
再简化一下结构:
下面是进一步优化后的抽象工厂模式的结构图:
Client
|
| 使用
V
[AbstractFactory]<>--------->[ConcreteFactory1]
| |
| |
V V
[AbstractProductA] [ConcreteProductA1]
| |
| |
V V
[ConcreteProductA2] [ConcreteProductB1]
在这个优化后的结构图中,去掉了不必要的细节,只保留了抽象工厂模式的核心部分。Client
通过抽象工厂来创建产品,而具体的产品创建细节被封装在具体的工厂类和具体的产品类中。这种简化后的结构图更加清晰地表达了抽象工厂模式的本质,使人更容易理解。
二、C++代码实现:
当使用抽象工厂模式时,我们需要定义抽象工厂接口和抽象产品接口,然后具体的工厂类和产品类要实现这些接口。以下是一个简单的C++实现示例:
#include <iostream>
// 抽象产品接口
class AbstractProductA {
public:
virtual void use() = 0;
};
class AbstractProductB {
public:
virtual void eat() = 0;
};
// 抽象工厂接口
class AbstractFactory {
public:
virtual AbstractProductA* createProductA() = 0;
virtual AbstractProductB* createProductB() = 0;
};
// 具体产品类
class ConcreteProductA1 : public AbstractProductA {
public:
void use() override {
std::cout << "Use product A1" << std::endl;
}
};
class ConcreteProductA2 : public AbstractProductA {
public:
void use() override {
std::cout << "Use product A2" << std::endl;
}
};
class ConcreteProductB1 : public AbstractProductB {
public:
void eat() override {
std::cout << "Eat product B1" << std::endl;
}
};
class ConcreteProductB2 : public AbstractProductB {
public:
void eat() override {
std::cout << "Eat product B2" << std::endl;
}
};
// 具体工厂类
class ConcreteFactory1 : public AbstractFactory {
public:
AbstractProductA* createProductA() override {
return new ConcreteProductA1();
}
AbstractProductB* createProductB() override {
return new ConcreteProductB1();
}
};
class ConcreteFactory2 : public AbstractFactory {
public:
AbstractProductA* createProductA() override {
return new ConcreteProductA2();
}
AbstractProductB* createProductB() override {
return new ConcreteProductB2();
}
};
int main() {
// 使用具体工厂1创建产品
AbstractFactory* factory1 = new ConcreteFactory1();
AbstractProductA* productA1 = factory1->createProductA();
AbstractProductB* productB1 = factory1->createProductB();
productA1->use();
productB1->eat();
// 使用具体工厂2创建产品
AbstractFactory* factory2 = new ConcreteFactory2();
AbstractProductA* productA2 = factory2->createProductA();
AbstractProductB* productB2 = factory2->createProductB();
productA2->use();
productB2->eat();
return 0;
}
在这个示例中,我们定义了抽象产品接口 AbstractProductA
和 AbstractProductB
,并分别有两个具体产品类实现它们。同时,我们定义了抽象工厂接口 AbstractFactory
,并有两个具体工厂类 ConcreteFactory1
和 ConcreteFactory2
分别实现它。在 main
函数中,我们使用具体工厂创建产品,并调用产品的方法。
这个示例展示了抽象工厂模式的基本实现,通过抽象工厂和抽象产品接口的定义,可以方便地扩展新的产品系列,并且客户端代码可以方便地切换不同的产品系列。
三、抽象工厂适用场景及特点:
抽象工厂模式适合以下场景和具有以下特点:
-
多个相关的产品系列:当系统需要一次性创建一整套相关的产品时,抽象工厂模式非常有用。例如,一个图形用户界面工具包可能需要创建按钮、文本框、下拉框等各种控件,这些控件之间存在关联,可以通过抽象工厂模式统一创建。
-
不同的产品等级结构:如果系统中存在不同的产品等级结构,而客户端需要使用一套产品族,抽象工厂模式可以提供一个统一的接口来创建不同等级结构的产品。
-
产品变化频率低:抽象工厂模式对于产品族的变化和扩展非常友好,但对于单个产品的变化不太友好。如果产品的变化频率较低,抽象工厂模式是一个很好的选择。
-
隐藏具体产品的实现:客户端只需要知道抽象产品的接口,而不需要关心具体产品的实现细节。这样可以降低客户端和具体产品类之间的耦合度。
-
易于替换产品系列:由于抽象工厂模式将产品的创建封装在工厂类中,因此可以轻松替换整个产品系列,而不需要修改客户端代码。
总的来说,抽象工厂模式适合于需要创建一系列相关或相互依赖的对象,并且希望将产品的创建和使用解耦的场景。通过抽象工厂模式,可以实现产品族的扩展和替换,同时保持客户端代码的稳定性和灵活性。
四、抽象工厂模式的优缺点:
4.1、抽象工厂模式优点:
-
产品族一致性:抽象工厂模式可以确保一次性创建一整套相关的产品,保证了这些产品之间的一致性,例如风格、主题等。
-
易于替换产品系列:由于抽象工厂模式将产品的创建封装在工厂类中,因此可以轻松替换整个产品系列,而不需要修改客户端代码。
-
隐藏具体产品的实现:客户端只需要知道抽象产品的接口,而不需要关心具体产品的实现细节。这样可以降低客户端和具体产品类之间的耦合度。
-
符合开闭原则:抽象工厂模式可以轻松地添加新的产品族,而不需要修改现有的代码,符合开闭原则。
-
提供一致的接口:抽象工厂模式提供了一致的接口来创建产品,这样可以让客户端代码更加简洁和易于维护。
4.2、抽象工厂模式缺点:
-
不易扩展产品等级结构:如果需要添加新的产品等级结构,比如增加新的按钮类型,需要修改抽象工厂接口和所有的具体工厂类,这可能会影响现有的代码。
-
产品变化频率高:如果产品的变化频率较高,抽象工厂模式可能会导致系统变得复杂,因为每次添加新产品都需要修改抽象工厂接口和所有的具体工厂类。
-
增加了系统的抽象性和理解难度:抽象工厂模式引入了额外的抽象层次,可能会增加系统的复杂性和理解难度。
总的来说,抽象工厂模式适合于需要创建一系列相关或相互依赖的对象,并且希望将产品的创建和使用解耦的场景。但是在产品等级结构经常变化的情况下,抽象工厂模式可能不是最佳选择。