C++ 设计模式——抽象工厂模式

news2024/11/18 2:28:53

抽象工厂模式

抽象工厂模式

    • 抽象工厂模式
      • 主要组成部分
      • 代码实现
      • 抽象工厂模式模式的 UML 图
      • 抽象工厂模式 UML 图解析
      • 优点和缺点
      • 适用场景

抽象工厂模式提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们的具体类。它通常用于需要创建多个产品族的场景。

引入“抽象工厂模式”设计模式的定义(实现意图):提供一个接口,让该接口负责创建一系列相关或者相互依赖的对象,而无须指定它们具体的类。

主要组成部分

  • 抽象工厂(AbstractFactory):定义创建抽象产品的接口。它声明了用于创建不同类型产品的方法。
  • 具体工厂(ConcreteFactory):实现抽象工厂接口,创建具体产品。每个具体工厂负责生成一组相关的具体产品。
  • 抽象产品(AbstractProduct):定义产品的接口。它为具体产品提供了一个公共的接口。
  • 具体产品(ConcreteProduct):实现抽象产品接口的具体类。每个具体产品对应于一个具体工厂。

代码实现

以下是使用抽象工厂模式创建不同类型的怪物对象的代码示例:

#include <iostream>
#include <string>

using namespace std;

// 怪物父类
class Monster {
public:
    Monster(int life, int magic, int attack) : m_life(life), m_magic(magic), m_attack(attack) {}
    virtual ~Monster() {} // 虚析构函数

protected:
    int m_life;    // 生命值
    int m_magic;   // 魔法值
    int m_attack;  // 攻击力
};

// 沼泽亡灵类怪物
class M_Undead_Swamp : public Monster {
public:
    M_Undead_Swamp(int life, int magic, int attack) : Monster(life, magic, attack) {
        cout << "一个沼泽的亡灵类怪物来到了这个世界" << endl;
    }
};

// 沼泽元素类怪物
class M_Element_Swamp : public Monster {
public:
    M_Element_Swamp(int life, int magic, int attack) : Monster(life, magic, attack) {
        cout << "一个沼泽的元素类怪物来到了这个世界" << endl;
    }
};

// 沼泽机械类怪物
class M_Mechanic_Swamp : public Monster {
public:
    M_Mechanic_Swamp(int life, int magic, int attack) : Monster(life, magic, attack) {
        cout << "一个沼泽的机械类怪物来到了这个世界" << endl;
    }
};

// 山脉亡灵类怪物
class M_Undead_Mountain : public Monster {
public:
    M_Undead_Mountain(int life, int magic, int attack) : Monster(life, magic, attack) {
        cout << "一个山脉的亡灵类怪物来到了这个世界" << endl;
    }
};

// 山脉元素类怪物
class M_Element_Mountain : public Monster {
public:
    M_Element_Mountain(int life, int magic, int attack) : Monster(life, magic, attack) {
        cout << "一个山脉的元素类怪物来到了这个世界" << endl;
    }
};

// 山脉机械类怪物
class M_Mechanic_Mountain : public Monster {
public:
    M_Mechanic_Mountain(int life, int magic, int attack) : Monster(life, magic, attack) {
        cout << "一个山脉的机械类怪物来到了这个世界" << endl;
    }
};

// 城镇亡灵类怪物
class M_Undead_Town : public Monster {
public:
    M_Undead_Town(int life, int magic, int attack) : Monster(life, magic, attack) {
        cout << "一个城镇的亡灵类怪物来到了这个世界" << endl;
    }
};

// 城镇元素类怪物
class M_Element_Town : public Monster {
public:
    M_Element_Town(int life, int magic, int attack) : Monster(life, magic, attack) {
        cout << "一个城镇的元素类怪物来到了这个世界" << endl;
    }
};

// 城镇机械类怪物
class M_Mechanic_Town : public Monster {
public:
    M_Mechanic_Town(int life, int magic, int attack) : Monster(life, magic, attack) {
        cout << "一个城镇的机械类怪物来到了这个世界" << endl;
    }
};

// 所有工厂类的父类
class M_ParFactory {
public:
    virtual Monster* createMonster_Undead() = 0; // 创建亡灵类怪物
    virtual Monster* createMonster_Element() = 0; // 创建元素类怪物
    virtual Monster* createMonster_Mechanic() = 0; // 创建机械类怪物
    virtual ~M_ParFactory() {} // 虚析构函数
};

// 沼泽地区的工厂
class M_Factory_Swamp : public M_ParFactory {
public:
    virtual Monster* createMonster_Undead() override {
        return new M_Undead_Swamp(300, 50, 120); // 创建沼泽亡灵类怪物
    }
    virtual Monster* createMonster_Element() override {
        return new M_Element_Swamp(200, 80, 110); // 创建沼泽元素类怪物
    }
    virtual Monster* createMonster_Mechanic() override {
        return new M_Mechanic_Swamp(400, 0, 90); // 创建沼泽机械类怪物
    }
};

// 山脉地区的工厂
class M_Factory_Mountain : public M_ParFactory {
public:
    virtual Monster* createMonster_Undead() override {
        return new M_Undead_Mountain(300, 50, 80); // 创建山脉亡灵类怪物
    }
    virtual Monster* createMonster_Element() override {
        return new M_Element_Mountain(200, 80, 100); // 创建山脉元素类怪物
    }
    virtual Monster* createMonster_Mechanic() override {
        return new M_Mechanic_Mountain(600, 0, 110); // 创建山脉机械类怪物
    }
};

// 城镇的工厂
class M_Factory_Town : public M_ParFactory {
public:
    virtual Monster* createMonster_Undead() override {
        return new M_Undead_Town(300, 50, 80); // 创建城镇亡灵类怪物
    }
    virtual Monster* createMonster_Element() override {
        return new M_Element_Town(200, 80, 100); // 创建城镇元素类怪物
    }
    virtual Monster* createMonster_Mechanic() override {
        return new M_Mechanic_Town(400, 0, 110); // 创建城镇机械类怪物
    }
};

// 使用示例
int main() {
    M_ParFactory* factory = new M_Factory_Swamp();

    Monster* undead = factory->createMonster_Undead();
    Monster* element = factory->createMonster_Element();
    Monster* mechanic = factory->createMonster_Mechanic();

    // 释放内存
    delete undead;
    delete element;
    delete mechanic;
    delete factory;

    return 0;
}

抽象工厂模式模式的 UML 图

在这里插入图片描述

抽象工厂模式 UML 图解析

  • 类与类之间的关系
    • Monster 类是所有具体怪物类的父类,子类(如 M_Undead_SwampM_Element_SwampM_Mechanic_Swamp 等)通过实线箭头与父类连接,箭头指向 Monster 类,表示继承关系。
    • M_ParFactory 是抽象工厂类,定义了创建不同类型怪物的接口。具体工厂类(如 M_Factory_SwampM_Factory_MountainM_Factory_Town)通过实线箭头与 M_ParFactory 类连接,表示继承关系。
  • 依赖关系
    • 具体工厂类(如 M_Factory_Swamp 等)与具体怪物类(如 M_Undead_Swamp 等)之间存在虚线箭头,表示依赖关系。具体工厂类负责实例化具体怪物类的对象,箭头指向被实例化的类。
  • 稳定与变化部分
    • 稳定部分Monster 类和 M_ParFactory 类是稳定部分,不需要频繁修改。
    • 变化部分:具体怪物类(如 M_Undead_SwampM_Element_Swamp 等)和具体工厂类(如 M_Factory_Swamp 等)属于变化部分。当需要添加新类型的怪物时,只需增加新的具体工厂类和具体怪物类,而不需要修改稳定部分。
  • 扩展性
    • 当需要引入新类型的怪物(如 M_Beast),只需创建一个新的具体工厂类(如 M_Factory_Beast)和对应的怪物类(如 M_Beast),而不需要更改现有的工厂接口。这符合开闭原则:对扩展开放,对修改关闭。
  • 隐藏实现细节
    • 如果 M_ParFactory 类及其具体实现由第三方开发,开发者只需通过抽象工厂接口与工厂交互,而无需了解具体的怪物类(如 M_Undead_Swamp 等),实现了对具体实现的隐藏。
  • 接口扩展
    • M_ParFactory 中的接口可以根据需要进行扩展,例如新增创建其他类型对象的方法(如 NPC),使得工厂能够支持更丰富的对象创建。

优点和缺点

优点

  • 解耦合:客户端代码与具体产品的实现解耦,便于维护和扩展。修改产品的实现不会影响到客户端。
  • 一致性:可以确保一组产品的一致性,避免在创建产品时出现不匹配的情况。例如,创建一个特定类型的怪物时,工厂会确保所有相关的属性和行为都符合预期。
  • 易于扩展:新增产品类型时,只需扩展工厂类和相应的产品类,而无需修改现有代码,符合开闭原则。
  • 隔离变化:将产品的创建逻辑集中在工厂中,减少了产品类之间的依赖,便于管理和控制变化。

缺点

  • 系统复杂性增加:引入抽象工厂模式会增加系统的复杂性,特别是在产品种类较多时,工厂类和产品类的数量也会增加。
  • 维护成本:随着产品族的增加,维护抽象工厂及其子类的成本可能会提升,特别是当需要对多个工厂进行修改时。
  • 难以支持新产品:如果需要支持新类型的产品,可能需要修改现有的工厂接口和实现,这可能导致较大的代码变动。
  • 运行时开销:由于使用了多层抽象,可能会引入一定的运行时开销,尤其是在频繁创建对象的场景中。

适用场景

  • 产品族的创建:当系统需要创建一组相关或相互依赖的产品时,使用抽象工厂模式可以确保产品的一致性和完整性。
  • 需要解耦的系统:当需要将产品的创建与使用分离,减少系统之间的耦合度时,抽象工厂模式是一个理想的选择。
  • 需要支持多个产品变体:在需要支持不同变体的情况下,例如不同地区的怪物、不同类型的用户界面组件等,抽象工厂模式可以有效管理这些变体。
  • 需要扩展产品类型:当系统需要频繁扩展新产品类型时,抽象工厂模式提供了良好的扩展机制,符合开闭原则。
  • 框架设计:在设计框架或库时,抽象工厂模式可以为用户提供灵活的产品创建接口,用户可以根据需要实现具体的工厂类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2052461.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电脑怎么截图?截屏电脑快捷键ctrl加什么?

截图是我们日常使用电脑过程中非常常见的操作之一。无论是想保存有用的信息、分享有趣的内容&#xff0c;还是记录某个错误信息&#xff0c;截图都是一个简单而有效的方式。但是&#xff0c;不同的操作系统和需求会决定使用不同的方法来截图。接下来&#xff0c;我们将详细介绍…

opencascade Bnd_Range源码学习区间计算

opencascade Bnd_Range 前言 这个类描述了由两个实数值限定的 1D 空间中的区间。 一个区间可以是无效的&#xff0c;这表示区间中不包含任何点。 方法 1 默认构造函数。创建一个无效区间。 Bnd_Range() &#xff1b; 2 构造函数。创建最小最大值区间 Bnd_Range(const Sta…

使用LoRA对Llama3微调

使用LoRA&#xff08;Low-Rank Adaptation of Large Language Models&#xff09;技术对Llama-3语言模型进行微调。 理论知识参考百度安全验证 微调的前提条件 现在huggingface上下载llama2或llama3的huggingface版本。 我下载的是llama-2-13b-chat。 大语言模型微调方法 …

ComfyUI的部署,Ubuntu22.04系统下——点动科技

在服务器Ubuntu22.04系统下&#xff0c;ComfyUI的部署 一、ubuntu22.04基本环境配置1.1 更换清华Ubuntu镜像源1.2 更新包列表&#xff1a;2. 安装英伟达显卡驱动2.1 使用wget在命令行下载驱动包2.2 更新软件列表和安装必要软件、依赖2.2 卸载原有驱动2.3 安装驱动2.4 安装CUDA2…

【实战】分组校验

在实际的业务场景中同一个Entity的校验可能会有不同的规则&#xff0c;比如添加数据品牌id必须为空&#xff0c;而更新数据品牌Id必须不为空&#xff0c;针对这种情况我们需要使用分组校验来实现 在Entity中指定分组规则 使用 /*** 保存*/RequestMapping("/save")pub…

[STM32]如何正确的安装和配置keil?(详细)

一、我们为什么需要keil? 对于嵌入式开发的硬件来讲STM32可以说有着不可撼动的地位&#xff0c;它可能是很多人入门嵌入式开发接触到的第一款芯片&#xff0c;其强大的生态和大量开放的源代码也深受开发者的喜爱。对于嵌入式开发的软件来讲&#xff0c;keil绝对是在一届软件中…

知识竞赛中限时答题环节竞赛规则有哪些设计方案

限时答题在知识竞赛活动中是一个比较新颖的玩法&#xff0c;通过在一定时间内快速答题来提高现场紧张气氛&#xff0c;达到很好的现场效果。这种方式要求选手不但要答题正确&#xff0c;还要答题速度。那么&#xff0c;常用的限时答题环节规则应怎么设计呢&#xff1f;下面列出…

智能数字矿山钻机机械设备类网站模板

智能数字矿山钻机设备类网站模板&#xff0c;非常高端大气上档次&#xff01;易优内容管理系统是一套专注中小型企业信息传播解决方案的管理系统&#xff0c;更是一套后台管理框架&#xff0c;可以通过个性定制导航入口&#xff0c;扩展前端多个场景&#xff0c;比如可以用于小…

后端开发刷题 | 链表内指定区间反转【链表篇】

描述 将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转&#xff0c;要求时间复杂度 O(n)O(n)&#xff0c;空间复杂度 O(1)O(1)。 例如&#xff1a; 给出的链表为 1→2→3→4→5→NULL1→2→3→4→5→NULL, m2,n4 返回 1→4→3→2→5→NULL 数据范围&#xff1a; 链表…

【Linux】【系统纪元】Linux基础指令

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《C游记》《进击的C》《Linux迷航》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、文件管理1.1 ls1.2 pwd1.3 cd1.4 mkdir1.5 touch1.6 rm1.7 cp1.8 mv 二、文件输出2.1 echo2.2 cat2.3 less…

新学期新动力,以骨传导耳机开启健康音乐之旅

大学生快开学啦&#xff01;激励自己在学期的状态给自己准备一个礼物应该不过分吧&#xff0c;相信没有大学生能够没有耳机&#xff01;不管是在赶早八的路上也要放收歌来醒醒神&#xff0c;还是日常散步不那么单调&#xff0c;使用频率都很高&#xff0c;但是入耳式的蓝牙耳机…

Stable Diffusion 提示词插件:开启个性化艺术创作大门,探索AI绘画新境界。让灵感枯竭再无可能!

前言 之前的文章介绍了提示词的基础用法和进阶用法&#xff0c;东西很多很复杂&#xff0c;那么非程序员相关行业的人员&#xff0c;对字符不敏感怎么办&#xff1f; 没关系&#xff0c;今天我来介绍几款提示词插件&#xff0c;可以大大提升 Stable Diffusion 的使用效率。 …

微信怎么恢复聊天记录?轻松4招,恢复消失的聊天记录

微信聊天记录不仅是日常沟通的桥梁&#xff0c;更是珍贵记忆的储存库。然而&#xff0c;误删、系统故障或设备更换等意外情况&#xff0c;时常让我们的聊天记录瞬间消失&#xff0c;给我们留下遗憾。面对这一挑战&#xff0c;微信怎么恢复聊天记录成为许多人的迫切需求。幸运的…

opensuse leap15安装配置

opensuse leap15安装配置 查看opensuse leap15安装完成后的基本配置关闭SELinux禁用AppArmor 关闭firewalld防火墙关闭polki服务&#xff08;非必须&#xff09;tuned服务安装必备软件 查看opensuse leap15安装完成后的基本配置 默认开启了防火墙默认开启了Linux安全模块 关闭…

day34 代码随想录 | 不同路径 整数拆分

不同路径 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。问总共有多少条不同的路径&#xff1f…

第37讲:Cephfs文件系统的正确使用姿势

文章目录 1.Cephfs文件系统简介2.Cephfs文件系统细节介绍2.1.Cephfs文件系统多客户端隔离挂载2.2.Ceph集群中多个Cephfs如何单独使用 3.挂载多个Cephfs文件系统4.Cephfs文件系统多客户端隔离挂载实战4.1.创建一个Cephfs文件系统4.2.将Cephfs文件系统挂载到本地路径4.3.在Cephfs…

JavaWeb - 认识web开发

JavaWeb Java和JavaWeb是两个不同的概念&#xff0c;它们在范围和应用上有所区别&#xff1a; Java&#xff1a; 定义&#xff1a;Java是一种面向对象的编程语言&#xff0c;由Sun Microsystems公司&#xff08;现已被Oracle收购&#xff09;于1995年推出。应用范围&#xff1…

易企秀场景秀源码系统全新升级,方便制作各种Html5应用的制作工具 带完整的安装代码包以及搭建部署教程

系统概述 在当今数字化的时代&#xff0c;Html5 应用已经成为了展示和传播信息的重要方式。而在众多的制作工具中&#xff0c;易企秀场景秀源码系统以其全新升级的功能和便捷性&#xff0c;吸引了众多用户的目光。它不仅为用户提供了方便制作各种 Html5 应用的工具&#xff0c…

亚马逊测评自养号:揭秘高效环境搭建的秘诀

亚马逊测评自养号环境搭建的技术要点主要涵盖了网络环境、IP管理、设备配置、浏览器防关联、支付卡选择与管理以及账号管理等多个方面。以下是对这些技术要点的详细解析&#xff1a; 1. 网络环境 使用国外服务器&#xff1a;在云端搭建安全终端&#xff0c;确保能够阻断硬件参…

【python基础】—离线环境下,在linux中安装python包(以sqlalchemy为例)

文章目录 第一步&#xff1a;在线环境下载离线安装包及依赖包。第二步&#xff1a;把包上传到离线环境的服务器上&#xff0c;进行安装。第三步&#xff1a;测试是否安装成功。常见报错之版本选择问题 第一步&#xff1a;在线环境下载离线安装包及依赖包。 下载第三方库官网&am…