在本章节中,我们将开始讨论五种创建型设计模式中的抽象工厂模式(Abstract Factory Pattern)。
理论部分
定义
- 抽象工厂模式是一种创建型设计模式,它提供一个接口用于创建相关或依赖对象的家族,而不需要明确指定具体类。
概括来说就是:可以看作是工厂模式多一个维度的扩展,就像一维数组和二维数组一样,工厂方法模式通常用来创建一类产品,而抽象工厂方法可以更灵活地创建多个类别——也就是有关联性的一组产品。
现在,我们要做一个奇幻风格的RPG游戏,我们使用武器和防具两套装备来定义角色。譬如战士的武器是剑🗡,防具是盾🛡;法师的武器是魔法杖🦯,防具是魔法书📕。
那么从拥有的装备角度考虑,就会产生两个维度了:武器和防具是一个维度,而武器是剑还是法杖,防具是盾还是魔法书,这又是一个维度。
所以我们就需要定义武器和防具的纯虚类,
// 武器接口
class Weapon
{
public:
virtual void use() = 0;
};
// 防具接口
class Armor
{
public:
virtual void equip() = 0;
};
所有具体的武器类都应该实现自己的使用逻辑,而所有的防具都应该实现自己的装备逻辑。
那么我们便可以写下具体的角色装备对象类定义了。
// 战士的剑
class Sword : public Weapon
{
void use() override
{
std::cout "挥舞剑!" std::endl;
}
};
// 战士的盾牌
class Shield : public Armor
{
void equip() override
{
std::cout "装备盾牌!" std::endl;
}
};
// 法师的法杖
class Staff : public Weapon
{
void use() override
{
std::cout "挥动法杖!" std::endl;
}
};
// 法师的魔法书
class Spellbook : public Armor
{
void equip() override
{
std::cout "翻阅魔法书!" std::endl;
}
};
它们分别是战士的武器剑、战士的防具盾牌,以及法师的武器法杖,和法师的防具魔法书。
当我们要使用抽象工厂模式时,我们需要定义装备工厂接口
// 装备工厂接口
class EquipmentFactory
{
public:
virtual Weapon* createWeapon() = 0;
virtual Armor* createArmor() = 0;
};
所有游戏角色的装备都应该拥有武器和防具两类对象,所以我们提供了对应的纯虚方法。
最后的步骤便是让我们具体生产游戏角色的工厂类,来实现装备工厂接口了。
// 战士工厂
class WarriorFactory : public EquipmentFactory
{
public:
Weapon* createWeapon() override
{
return new Sword(); // 战士的剑
}
Armor* createArmor() override
{
return new Shield(); // 战士的盾牌
}
};
// 法师工厂
class MageFactory : public EquipmentFactory
{
public:
Weapon* createWeapon() override
{
return new Staff(); // 法师的法杖
}
Armor* createArmor() override
{
return new Spellbook(); // 法师的魔法书
}
};
战士工厂在创建武器时实例化剑,在创建防具时实例化盾牌;
法师工厂在创建武器时实例化法杖,在创建防具时实例化魔法书。
定义完工厂后我们对游戏角色类的设计就可以编写这样的代码:
// 角色类
class Character
{
public:
Character(EquipmentFactory* factory) : factory(factory) { }
void equip()
{
Weapon* weapon = factory->createWeapon();
Armor* armor = factory->createArmor();
weapon->use();
armor->equip();
}
private:
EquipmentFactory* factory;
};
角色在构造时传入装备工厂对象,在穿戴装备的逻辑中通过工厂的方法来创建武器和防具实例,再分别调用它们的使用方法。
// 创建战士
EquipmentFactory* warriorFactory = new WarriorFactory();
Character warrior(warriorFactory);
warrior.equip(); // 使用剑和盾
// 创建法师
EquipmentFactory* mageFactory = new MageFactory();
Character mage(mageFactory);
mage.equip(); // 使用法杖和魔法书
那么将在控制台输出以下内容:
挥舞剑!
装备盾牌!
施法!
翻阅魔法书!
也就是说,经过层层封装,装备工厂、游戏角色和道具三部分的职责都十分明确了,我们写下的代码也是语义清晰有条理的,甚至可以不借助任何注释就能读懂。
现在我们就可以来总结以下抽象工厂模式的构成要素了。
【构成要素】
- 抽象产品
如:Weapon和Armor基类(纯虚类),我们通过它们来约定具体产品的接口声明,限制它们必须具有的功能。
- 具体产品
如:Sword、Shield、Staff和Spellbook子类,它们时最终被抽象工厂实例化的目标。
- 抽象工厂
如:EquipmentFactory,它负责声明一组接口来创建抽象产品,随后定义的所有具体工厂都应该能够生成对应的成套产品。
- 具体工厂
如:WarriorFactory和MageFactory子类,负责实例化具体的产品,我们的客户端只需要通过调用抽象工厂接口,就能完成与具体工厂和产品的交互。
- 客户端(Client):使用抽象工厂和抽象产品接口
与工厂方法模式的区别
-
工厂方法模式:创建单一产品
-
抽象工厂模式:创建产品家族(一组相关产品)
【应用场景】
- 跨平台GUI框架
Qt、GTK+、wxWidgets对不同平台的不同UI组件进行封装
- 游戏开发
针对Windows、Playstation等不同平台供读写方法来完成存档功能
为不同风格(科幻、奇幻、现代)创建一套相关的游戏对象(角色、武器、建筑等)
- 游戏或者应用软件的界面主题风格
针对不同主题实现不同的UI组件时可以灵活切换
- RHI(Rendering Hardware Interface)
对纹理、着色器、缓冲区进行抽象兼容OpenGL、Vulkan和DirectX等不同后端
- 跨平台网络库
在Windows上使用WinSock、在Linux上使用PosixSocket
- 数据库访问
支持多种数据库系统(MySQL、PostgreSQL等),每个系统有自己的一套相关对象(连接、命令、适配器等)
最后我们还需要了解抽象工厂模式的优缺点。
【优缺点】
- 优点
更多维度的可定制化,可以针对不同的产品变种提供具体的创建逻辑。
确保产品兼容性:一个工厂创建的所有产品都是设计为一起工作的
避免客户端与具体产品类耦合:客户端只通过抽象接口使用产品
单一职责原则:产品创建代码集中在一个位置,便于维护
开闭原则:引入新的产品变体很容易,无需修改现有代码
- 缺点
更多的类,代码更多,抽象和理解的过程更为复杂一些。
难以支持新种类的产品:如果需要添加新产品到家族中,需要修改抽象工厂及其所有具体实现
总结
抽象工厂模式是工厂方法模式的扩展,它关注于创建产品家族而不是单个产品。通过使用抽象工厂,可以确保创建的对象是兼容的,并且客户端代码与具体类解耦。这种模式特别适用于需要确保一系列相关产品一起工作的场景,如跨平台应用、主题系统等。
文章来源于互联网:抽象工厂模式(Abstract Factory Pattern)
深度学习中的Zero-shot(零次学习) 1 Zero-shot介绍 1.1 基本原理 1.3 发展趋势 2 典型算法 2.1 属性标签嵌入法 2.2 基于语义嵌入的方法 2.3 生成模型方法 2.4 基于图模型的方法 2.5 基于深度学习的方法 3 应用场…
5bei.cn大模型教程网










