当前位置: 首页 > news >正文

创建型模式--2.简单工厂模式【人造恶魔果实工厂1】

1. 工厂模式的特点

在海贼王中,作为原王下七武海之一的多弗朗明哥,可以说是新世界最大的流氓头子,拥有无上的权利和无尽的财富。他既是德雷斯罗萨国王又是地下世界的中介,控制着世界各地的诸多产业,人造恶魔果实工厂就是其中之一。
在这里插入图片描述

人造恶魔果实的最大买家是四皇之一的凯多凯多其实很明智,他没有自己去生产,可能有这么几个因素:

  • 凯多手下没有像凯撒·库朗一样的科学家,无法掌握生产人造恶魔果实这种顶级的科学技术【意味着构造一个对象有时候需要经历一个非常复杂的操作流程,既然麻烦那索性就不干了】。
  • 有需求下单就行,只需关心结果,无需关心过程【实现了解耦合】。
  • 人造恶魔果实出了问题,自己无责任,售后直接找明哥【便于维护】。

在我们现实生活中也是一样,买馒头和自己蒸馒头、去饭店点一份大盘鸡和自己养鸡,杀鸡,做大盘鸡,这是全然不同的两种体验:

  • 自己做麻烦,而且有失败的风险,需要自己承担后果。
  • 买现成的,可以忽略制作细节,方便快捷并且无风险,得到的肯定是美味的食物。

对于后者,就相当于是一个加工厂,通过这个工厂我们就可以得到想要的东西,在程序设计中,这种模式就叫做工厂模式,工厂生成出的产品就是某个类的实例,也就是对象。关于工厂模式一共有三种,分别是:简单工厂模式、工厂模式、抽象工厂模式

通过上面人造恶魔果实的例子,我们能够了解到,不论使用哪种工厂模式其主要目的都是实现类与类之间的解耦合,这样我们在创建对象的时候就变成了拿来主义,使程序更加便于维护。在本节中,先介绍简单工厂模式。

基于简单工厂模式去创建对象的时候,需要提供一个工厂类,专门用于生产需要的对象,这样关于对象的创建操作就被剥离出去了。

简单工厂模式相关类的创建和使用步骤如下:

  1. 创建一个新的类, 可以将这个类称之为工厂类。对于简单工厂模式来说,需要的工厂类只有一个。
  2. 在这个工厂类中添加一个公共的成员函数,通过这个函数来创建我们需要的对象,关于这个函数一般将其称之为工厂函数。
  3. 关于使用,首先创建一个工厂类对象,然后通过这个对象调用工厂函数,这样就可以生产出一个指定类型的实例对象了。

2. 生产的产品

在海贼世界中,凯撒·库朗研制的人造恶魔果实是有瑕疵的,吃下人造恶魔果实的失败品没能成功获得果实能力的人,会被剥夺除笑以外的一切表情,所以人造恶魔果实被称为SMILE

在这里插入图片描述

下面是明哥的SMILE工厂要生产的众多人造动物系恶魔果实中的三种:

// 人造恶魔果实· 绵羊形态
class SheepSmile
{
public:void transform(){cout << "变成人兽 -- 山羊人形态..." << endl;}void ability(){cout << "将手臂变成绵羊角的招式 -- 巨羊角" << endl;}
};// 人造恶魔果实· 狮子形态
class LionSmile
{
public:void transform(){cout << "变成人兽 -- 狮子人形态..." << endl;}void ability(){cout << "火遁· 豪火球之术..." << endl;}
};// 人造恶魔果实· 蝙蝠形态
class BatSmile
{
public:void transform(){cout << "变成人兽 -- 蝙蝠人形态..." << endl;}void ability(){cout << "声纳引箭之万剑归宗..." << endl;}
};

不论是吃了那种恶魔果实,获得了相应的能力之后,可以做的事情大体是相同的,那就是形态变化transform() 和 使用果实能力alility()

另外,生产这些恶魔果实的时候可能需要极其复杂的参数,在此就省略了【也就是说这些类的构造函数的参数在此被省略了】。

3. 如何生产

如果想要生产出这些恶魔果实,可以先创建一个工厂类,然后再给这个工厂类添加一个工厂函数,又因为我们要生成三种不同类型的恶魔果实,所以可以给工厂函数添加一个参数,用以控制当前要生产的是哪一类。

enum class Type:char{SHEEP, LION, BAT};
// 恶魔果实工厂类
class SmileFactory
{
public:enum class Type:char{SHEEP, LION, BAT};SmileFactory() {}~SmileFactory() {}void* createSmile(Type type){void* ptr = nullptr;switch (type){case Type::SHEEP:ptr = new SheepSmile;break;case Type::LION:ptr = new LionSmile;break;case Type::BAT:ptr = new BatSmile;break;default:break;}return ptr;}
};int main()
{SmileFactory* factory = new SmileFactory;BatSmile* batObj = (BatSmile*)factory->createSmile(Type::BAT);return 0;
}
  • 关于恶魔果实的类型,上面的类中用到了强类型枚举(C++11新特性),增强了代码的可读性,并且将枚举元素设置为了char类型,节省了内存。
  • 函数createSmile(Type type)的返回值是void*类型,这样处理主要是因为每个case 语句创建出的对象类型是不一样的,为了实现兼容,故此这样处理。
  • 得到函数createSmile(Type type)的返回值之后,还需要将其转换成实际的类型,处理起来还是比较繁琐的。
    关于工厂函数的返回值,在C++中还有一种更好的解决方案,就是使用多态。如果想要实现多态,需要满足三个条件:
  • 类和类之间有继承关系。
  • 父类中有虚函数,并且在子类中需要重写这些虚函数。
  • 使用父类指针或引用指向子类对象。

所以,我们需要给人造恶魔果实提供一个基类,然后让上边的三个类SheepSmile、LionSmile、BatSmile作为子类继承这个基类。根据分析我们就有画出简单工厂模式的UML类图了:

在这里插入图片描述

根据UML类图,编写出的代码如下:

#include <iostream>
using namespace std;class AbstractSmile
{
public:virtual void transform() {}virtual void ability() {}virtual ~AbstractSmile() {}
};
// 人造恶魔果实· 绵羊形态
class SheepSmile : public AbstractSmile
{
public:void transform() override{cout << "变成人兽 -- 山羊人形态..." << endl;}void ability() override{cout << "将手臂变成绵羊角的招式 -- 巨羊角" << endl;}
};// 人造恶魔果实· 狮子形态
class LionSmile : public AbstractSmile
{
public:void transform() override{cout << "变成人兽 -- 狮子人形态..." << endl;}void ability() override{cout << "火遁· 豪火球之术..." << endl;}
};class BatSmile : public AbstractSmile
{
public:void transform() override{cout << "变成人兽 -- 蝙蝠人形态..." << endl;}void ability() override{cout << "声纳引箭之万剑归宗..." << endl;}
};// 恶魔果实工厂类
enum class Type:char{SHEEP, LION, BAT};
class SmileFactory
{
public:SmileFactory() {}~SmileFactory() {}AbstractSmile* createSmile(Type type){AbstractSmile* ptr = nullptr;switch (type){case Type::SHEEP:ptr = new SheepSmile;break;case Type::LION:ptr = new LionSmile;break;case Type::BAT:ptr = new BatSmile;break;default:break;}return ptr;}
};int main()
{SmileFactory* factory = new SmileFactory;AbstractSmile* obj = factory->createSmile(Type::BAT);obj->transform();obj->ability();return 0;
}

通过上面的代码,我们实现了一个简单工厂模式,关于里边的细节有以下几点需要说明:

  1. 由于人造恶魔果实类有继承关系, 并且实现了多态,所以父类的析构函数也应该是虚函数,这样才能够通过父类指针或引用析构子类的对象。

  2. 工厂函数createSmile(Type type)的返回值修改成了AbstractSmile*类型,这是人造恶魔果实类的基类,通过这个指针保存的是子类对象的地址,这样就实现了多态,所以在main()函数中,通过obj对象调用的实际是子类BatSmile中的函数,因此打印出的信息应该是这样的:

变成人兽 -- 蝙蝠人形态...
声纳引箭之万剑归宗...

相关文章:

创建型模式--2.简单工厂模式【人造恶魔果实工厂1】

1. 工厂模式的特点 在海贼王中&#xff0c;作为原王下七武海之一的多弗朗明哥&#xff0c;可以说是新世界最大的流氓头子&#xff0c;拥有无上的权利和无尽的财富。他既是德雷斯罗萨国王又是地下世界的中介&#xff0c;控制着世界各地的诸多产业&#xff0c;人造恶魔果实工厂就…...

一些考研经验

前言 考研结束已有半个月&#xff0c;之前一直想写经验贴&#xff0c;奈何感觉自己本身就比较菜&#xff0c;考了两年才堪堪上岸&#xff0c;所以有些犹豫&#xff0c;拖拖沓沓到现在&#xff0c;思虑再三最终决定把自己对于考研的一些拙见记录一下&#xff0c;供各位参考。 …...

StockTrading AI小模型股票自动交易系统 转载

Stock-Trading StockTrading AI小模型股票自动交易系统 项目文档 Stock-Trading 语雀 项目展示 功能介绍 对接证券平台&#xff0c;实现股票自动化交易使用QuartZ定时任务调度&#xff0c;每日自动更新数据使用DL4J框架实现LSTM模型指导股票买入&#xff0c;采用T1短线交易策…...

01背包问题合集 蓝桥OJ

一、蓝桥OJ 1174小明的背包1 模板题 思路&#xff1a; 用二维数组dp判断最大价值&#xff0c;i表示物品数量&#xff0c;j表示物品体积&#xff0c;如果 j > V 则无需继续&#xff0c; j > w 物品还能再增加&#xff0c;同样价值也增加&#xff0c;否则继承之前的价值&am…...

Nuxt3 实战 (三):使用 release-it 自动管理版本号和生成 CHANGELOG

release-it 能做什么&#xff1f; 增加版本号并提交 Git生成变更日志&#xff08;Changelog&#xff09;并提交到 Git创建 Git 标签并推送到远程仓库发布到 npm 等软件仓库在 GitHub、GitLab 等平台创建发行版 前置知识 在看这篇文章之前&#xff0c;我们有必要了解一下 Sem…...

鸿蒙OS开发实战:【自动化测试框架】使用指南

概述 为支撑HarmonyOS操作系统的自动化测试活动开展&#xff0c;我们提供了支持JS/TS语言的单元及UI测试框架&#xff0c;支持开发者针对应用接口进行单元测试&#xff0c;并且可基于UI操作进行UI自动化脚本的编写。 本指南重点介绍自动化测试框架的主要功能&#xff0c;同时…...

算法(二分查找)

1.给你一个非负整数 x &#xff0c;计算并返回 x 的 算术平方根 。 由于返回类型是整数&#xff0c;结果只保留 整数部分 &#xff0c;小数部分将被 舍去 。 注意&#xff1a;不允许使用任何内置指数函数和算符&#xff0c;例如 pow(x, 0.5) 或者 x ** 0.5 。 示例 1&#xf…...

运筹学基础(六)列生成算法(Column generation)

文章目录 前言从Cutting stock problem说起常规建模Column generation reformulation 列生成法核心思想相关概念Master Problem (MP)Linear Master Problem (LMP)Restricted Linear Master Problem (RLMP)subproblem&#xff08;核能预警&#xff0c;非常重要&#xff09; 算法…...

[阅读笔记] 电除尘器类细分市场2023年报

0.原始链接&#xff1a; 2023年除尘行业评述及2024年发展展望-北极星大气网 中国环保产业协会 供稿 1.重要信息摘录 市场占有率最大的是电除尘和袋式除尘行业装备产品名录: 国家鼓励发展的重大环保技术装备目录&#xff08;2023年版&#xff09;权威评审机构&#xff1a;…...

Kubernetes学习笔记11

k8s集群核心概念&#xff1a;pod&#xff1a; 在K8s集群中是不能直接运行容器的&#xff0c;K8s的最小调度单元是Pod&#xff0c;我们要使用Pod来运行应用程序。 学习目标&#xff1a; 了解pod概念&#xff1a; 了解查看pod方法 了解创建pod方法 了解pod访问方法 了解删除…...

✌2024/4/3—力扣—无重复字符的最长子串

代码实现&#xff1a; 解法一&#xff1a;暴力法 int lengthOfLongestSubstring(char *s) {int hash[256] {0};int num 0;for (int i 0; i < strlen(s); i) {int count 0;for (int j i; j < strlen(s); j) {if (hash[s[j]] 0) {hash[s[j]];count;num num > cou…...

Tauri 进阶使用与实践指南

Tauri 进阶使用与实践指南 调试技术 在 Tauri 应用开发中&#xff0c;调试分为两大部分&#xff1a;Web 端与 Rust 控制台。 Web 端调试 在 Web 端界面&#xff0c;可以直接采用浏览器内置的开发者工具进行调试。在 Windows 上&#xff0c;可以通过快捷键 Ctrl Shift i 打…...

2024年最新社交相亲系统源码下载

最新相亲系统源码功能介绍 参考&#xff1a;相亲系统源码及功能详细介绍 相亲系统主要功能 &#xff08;已完成&#xff09; 相亲系统登录注册 相亲系统会员列表 相亲系统会员搜索 相亲系统会员详情 相亲系统会员身份认证 - 对接阿里云 相亲系统资源存储 - 对接七…...

git知识

如何将develop分支合并到master分支 #简单版 git checkout master git pull origin master git merge origin/develop # 解决可能的冲突并提交 git push origin master#复杂版 git checkout master # 拉取远程 master 分支的最新代码并合并到本地 git pull origin master # 拉…...

代码随想录算法训练营第三十五天|860.柠檬水找零、406.根据身高重建队列、452.用最少数量的箭引爆气球

代码随想录算法训练营第三十五天|860.柠檬水找零、406.根据身高重建队列、452.用最少数量的箭引爆气球 860.柠檬水找零 在柠檬水摊上&#xff0c;每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品&#xff0c;&#xff08;按账单 bills 支付的顺序&#xff09;一次购买一杯…...

golang defer实现

derfer : 延迟调用&#xff0c;函数结束返回时执行&#xff0c;多个defer按照先进后出的顺序调用 原理&#xff1a;底层通过链表实现&#xff0c;每次新增的defer调用&#xff0c;通过头插法插入链表&#xff1b;defer执行时&#xff0c;从链表头开始遍历&#xff0c;相当于实…...

数据仓库实践

什么是数据仓库&#xff1f; 数据仓库是一个用于存储大量数据并支持数据分析与报告的系统。它通常用于集成来自不同来源的数据&#xff0c;提供一个统一的视图&#xff0c;以便进行更深入的分析和决策。 数据仓库的主要优势&#xff1f; 决策支持&#xff1a;为企业决策提供可靠…...

深入浅出 -- 系统架构之微服务标准组件及职责

我们来认识一下微服务架构在Java体系中依托哪些组件实现的。 相对于单体架构的简单粗暴&#xff0c;微服务的核心是将应用打散&#xff0c;形成多个独立提供的微服务&#xff0c;虽然从管理与逻辑上更符合业务需要。但微服务架构也带来了很多急需解决的核心问题&#xff1a; 1…...

IP协议中的四大支柱:DHCP、NAT、ICMP和IGMP的功能剖析

DHCP动态获取 IP 地址 我们的电脑通常都是通过 DHCP 动态获取 IP 地址&#xff0c;大大省去了配 IP 信息繁琐的过程。 客户端首先发起 DHCP 发现报文&#xff08;DHCP DISCOVER&#xff09; 的 IP 数据报&#xff0c;由于客户端没有 IP 地址&#xff0c;也不知道 DHCP 服务器的…...

基于Socket简单的UDP网络程序

⭐小白苦学IT的博客主页 ⭐初学者必看&#xff1a;Linux操作系统入门 ⭐代码仓库&#xff1a;Linux代码仓库 ❤关注我一起讨论和学习Linux系统 1.前言 网络编程前言 网络编程是连接数字世界的桥梁&#xff0c;它让计算机之间能够交流信息&#xff0c;为我们的生活和工作带来便利…...

计算机思维

计算机思维是一种运用计算机科学的基础概念和方法来解决问题、设计系统和理解人类行为的思维方式。它包括以下几个方面&#xff1a; 1. 抽象和建模&#xff1a;将复杂的现实问题抽象为计算机可以处理的模型&#xff0c;通过定义对象、属性和关系来构建问题的逻辑结构。 2. 算法…...

如何判断一个linux机器是物理机还是虚拟机

https://blog.csdn.net/qq_32262243/article/details/132571117 第一种方式&#xff1a;dmesg命令 [rootnshqae01adm03 ~]# dmesg | grep -i hypervisor [ 0.000000] Hypervisor detected: Xen PV [ 1.115297] VPMU disabled by hypervisor. 在我的机器上 dmesg也是能够用来判…...

python用requests的post提交data数据以及json和字典的转换

环境&#xff1a;python3.8.10 python使用requests的post提交数据的时候&#xff0c;代码写法跟抓包的headers里面的Content-Type有关系。 &#xff08;一&#xff09;记录Content-Type: application/x-www-form-urlencoded的写法。 import requestsurlhttps://xxx.comheade…...

【Datax分库分表导数解决方法】MySQL_to_Hive

Datax-MySQL_to_Hive-分库分表-数据同步工具 简介&#xff1a; 本文档介绍了一个基于Python编写的工具&#xff0c;用于实现分库分表数据同步的功能。该工具利用了DataX作为数据同步的引擎&#xff0c;并通过Python动态生成配置文件&#xff0c;并调用DataX来执行数据同步任务…...

Vue2 —— 学习(一)

目录 一、了解 Vue &#xff08;一&#xff09;介绍 &#xff08;二&#xff09;Vue 特点 &#xff08;三&#xff09;Vue 网站 1.学习&#xff1a; 2.生态系统&#xff1a; 3.团队 二、搭建 Vue 开发环境 &#xff08;一&#xff09;安装与引入 Vue 1.直接引入 2.N…...

Windows Server 2008添加Web服务器(IIS)、WebDAV服务、网络负载均衡

一、Windows Server 2008添加Web服务器&#xff08;IIS&#xff09; &#xff08;1&#xff09;添加角色&#xff0c;搭建web服务器&#xff08;IIS&#xff09; &#xff08;2&#xff09;添加网站&#xff0c;关闭默认网页&#xff0c;添加默认文档 在客户端浏览器输入服务器…...

SpringMVC转发和重定向

转发和重定向 1. View Resolver Spring MVC 中的视图解析器&#xff08;View Resolver&#xff09;负责解析视图。可以通过在配置文件中定义一个 View Resolver 来配置视图解析器&#xff1a; 配置文件版&#xff1a;spring-web.xml <!-- for jsp --> <bean class&q…...

勒索病毒最新变种.rmallox勒索病毒来袭,如何恢复受感染的数据?

导言&#xff1a; 随着信息技术的飞速发展&#xff0c;网络安全问题日益突出&#xff0c;其中勒索病毒便是近年来备受关注的网络安全威胁之一。在众多勒索病毒中&#xff0c;.rmallox勒索病毒以其独特的传播方式和强大的加密能力&#xff0c;给广大用户带来了极大的困扰。本文…...

复试专业课问题

1、数据结构&#xff1a;详细描述归并排序的过程 归并排序是用分治思想&#xff0c;分治模式在每一层递归上有三个步骤&#xff1a; 分解&#xff08;Divide&#xff09;&#xff1a;将n个元素分成个含n/2个元素的子序列。解决&#xff08;Conquer&#xff09;&#xff1a;用…...

比特币革命:刚刚开始

作者&#xff1a;Marius Farashi Tasooji 编译&#xff1a;秦晋 要充分理解比特币及其含义&#xff0c;首先必须理解什么是价值&#xff0c;什么是货币。以及是什么赋予资产价值&#xff1f; 这个问题看似愚蠢&#xff0c;但实际上非常有趣。我们的生活是由我们消费或出售的物品…...