基础理解
Q:抽象工厂与简单工厂有什么不同
A:抽象工厂适用于一个产品下面有许多具体的子产品,而简单工厂则是只有一个单一的产品。所以抽象工厂在使用中会多一些。
Q:抽象工厂的应用场景
A:首先你要懂得简单工厂的思路用法,如果你需要与多个不同系列(椅子,沙发)的相关产品(维多利亚,现代)交互, 但是由于无法提前获取具体产品类 (现代椅子 ), 或者出于对未来扩展性的考虑, 你不希望代码基于产品的具体类进行构建,在这种情况下, 你可以使用抽象工厂。
跳转观看简单工厂
注意点
- 兼容性:确保由同一抽象工厂创建的所有产品都是兼容的,并且可以系统中无缝地进行交互和替换。
- 管理变体:确保每个变体都有对应的工厂,并且工厂创建的产品能够符合该变体的特性和要求。
- 足够抽象:遵循循依赖倒置原则,即高层模块不应该依赖于具体的实现细节,而应该依赖于抽象
在我下面写的代码中,ClientCode(客户端) 依赖于抽象类(抽象工厂AbstractFactory) 不具体依赖于是维多利亚工厂 或 现代工厂
创建抽象工厂
例如我们有:
- 椅子种类:维多利亚椅子 现代椅子…
- 沙发种类:维多利亚沙发 现代沙发…
拆分一下椅子种类

我们需要声明抽象工厂(AbstractFactory)——包含系列中所有产品构造方法的接口:Creat_Chair 和 Creat_Sofa
基于抽象工厂类创建 具体分支的工厂:维多利亚工厂 和 现代工厂 (维多利亚工厂只能创建维多利亚椅子,和维多利亚沙发)

UML图
看个大体,明白之间的关系即可
空心箭头:继承关系
虚线箭头:依赖
实线箭头:关联

#include <bits/stdc++.h>
using namespace std;
/**
产品家族的每个不同产品都应该有一个基础接口。产品的所有变体都必须实现这个接口。
*/
class Chair
{
public:
virtual ~Chair(){};
virtual std::string name() const = 0;
};
class VictorianChair : public Chair
{
public:
std::string name() const override
{
return "维多利亚椅子\n";
}
};
class ModernChair : public Chair
{
std::string name() const override
{
return "现代椅子\n";
}
};
/**
这是另一个产品的基础接口。所有产品可以相互交互,但是只有相同具体变体的产品之间才可能进行适当的交互。
*/
class Sofa
{
public:
virtual ~Sofa(){};
virtual std::string name() const = 0;
/**
* ...但它也可以与Chair合作。
* 抽象工厂确保其创建的所有产品都属于同一变体,因此是相容的。
*/
virtual std::string combination(const Chair &collaborator) const = 0; // combination:组合
};
/**
*维多利亚产品由相应的维多利亚工厂生产。
*/
class VictorianSofa : public Sofa
{
public:
std::string name() const override
{
return "维多利亚沙发\n";
}
/**
变体 维多利亚沙发只能与变体 维多利亚椅子 正确地配合使用。然而,它可以接受任何 椅子Chair 的实例作为参数。
*/
std::string combination(const Chair &collaborator) const override
{
const std::string result = collaborator.name();
return "给你送来 维多利亚沙发 和 " + result + " ";
}
};
class ModernSofa : public Sofa
{
public:
std::string name() const override
{
return "现代沙发\n";
}
std::string combination(const Chair &collaborator) const override
{
const std::string result = collaborator.name();
return "给你送来 现代沙发 和 " + result + " ";
}
};
/**
抽象工厂接口声明了一组方法,这些方法返回不同的抽象产品。这些产品被称为一个家族,它们之间由一个高层次的主题或概念相关联。一个产品家族可能有几个变体,但一个变体的产品与另一个变体的产品不兼容。
*/
class AbstractFactory
{
public:
virtual Chair *Creat_Chair() const = 0;
virtual Sofa *Creat_Sofa() const = 0;
};
/**
具体工厂生产属于单个变体的产品家族。工厂确保生成的产品是相容的。请注意,具体工厂方法的签名返回一个抽象产品,而在方法内部实例化一个具体产品。
*/
class VictorianFactory : public AbstractFactory
{
public:
Chair *Creat_Chair() const override
{
return new VictorianChair();
}
Sofa *Creat_Sofa() const override
{
return new VictorianSofa();
}
};
class ModernFactory : public AbstractFactory
{
public:
Chair *Creat_Chair() const override
{
return new ModernChair();
}
Sofa *Creat_Sofa() const override
{
return new ModernSofa();
}
};
/**
客户端代码只通过抽象类型 抽象工厂 和 抽象产品(椅子,沙发) 与工厂和产品进行交互。这样可以在不破坏客户端代码的情况下传递任何工厂或产品的子类。
*/
void ClientCode(const AbstractFactory &factory)
{
const Chair *product_a = factory.Creat_Chair();
const Sofa *product_b = factory.Creat_Sofa();
std::cout << product_b->name() << "\n";
std::cout << product_b->combination(*product_a) << "\n";
delete product_a;
delete product_b;
}
int main()
{
std::cout << "Client: 测试维多利亚工厂:\n";
VictorianFactory *f1 = new VictorianFactory();
ClientCode(*f1);
delete f1;
std::cout << std::endl;
std::cout << "Client: 测试现代工厂:\n";
ModernFactory *f2 = new ModernFactory();
ClientCode(*f2);
delete f2;
system("pause");
return 0;
}
优缺点
| 优点 | 缺点 |
|---|---|
| 确保同一工厂生成的产品相互匹配。 | 采用该模式需要向应用中引入众多接口和类, 代码可能会比之前更加复杂。 |
| 避免客户端和具体产品代码的耦合。 | |
| 单一职责原则。 同一种类的产品生成代码在到同一位置, 易于维护。 | |
| 开闭原则。 引入新产品变体时, 无需修改客户端代码。 |
与其他模式的关系
- 抽象工厂可以用单例模式来实现。(只存在一个抽象工厂)
- 设计工作的初期都会使用 简单工厂 (较为简单, 而且可以更方便地通过子类进行定制), 随后演化为使用抽象工厂模式(更灵活但更加复杂)。
- 抽象工厂模式通常基于一组工厂方法, 但你也可以使用原型模式来生成这些类的方法。
原型工厂方法模式中,工厂方法不是直接创建产品的新实例,而是基于现有的原型(Prototype)对象创建新的产品实例。这种方式可以在需要创建新实例时避免耗费资源来实例化新对象,而是通过复制现有对象来创建新实例。
- 当只需对客户端代码隐藏子系统创建对象的方式时, 你可以使用抽象工厂来代替外观模式。(外观模式是隐藏整个代码)
- 你可以将抽象工厂和桥接模式搭配使用。 如果由桥接定义的抽象只能与特定接口API实现合作。(当这个抽象使用这个工厂,就会生产出符合这个抽象所需要的具体接口API)

如果有错还望指正。谢谢大家。
参考文章
492





