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

news2024/11/25 19:52:39

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中的函数,因此打印出的信息应该是这样的:

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

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

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

相关文章

Java Web这一路走来

大部分Java应用都是Web或网络应用&#xff0c;MVC框架在Java框架中有着举足轻重的地位&#xff0c;一开始的Web应用并不现在这样子的&#xff0c;一步一步走来&#xff0c;每一步都经历了无数的血和泪的教训&#xff0c;以史为镜可以知兴替。 1. 草莽时代 早期的Java服务端技…

使用ollydbg还原密码程序的密码

前言&#xff1a;我们上次用ida pro破解了程序密码这次我们换个工具来还原程序密码 第一步 和上次一样把找到的程序拖到ollydbg里面 第二步 右键点击查找所有引用字符串 第三步 找到报错代码双击进入 第五步 找到上面的jnz双击将其改成jz 第六步 将所修改的保存点击空白…

FPGA(Verilog)实现uart传输协议传输数据(含仿真)

目录 实现功能&#xff1a; 1.接收uart串行数据&#xff0c;输出并行数据(1byte)。 2.输入并行数据(1byte)&#xff0c;输出uart串行数据。 3.完成uart传输的1次环回。 uart协议的1帧数据传输 模块封装-port设置 Verilog代码实现 1.uart接收模块:接收串行数据,输出并行数…

基于Java+SpringBoot+Vue企业员工管理系统(源码+文档+部署+讲解)

一.系统概述 随着社会的发展&#xff0c;系统的管理形势越来越严峻。越来越多的用户利用互联网获得信息&#xff0c;但各种信息鱼龙混杂&#xff0c;信息真假难以辨别。为了方便用户更好的获得信息&#xff0c;因此&#xff0c;设计一种安全高效的员工管理系统极为重要。 为设计…

swiftui macOS实现加载本地html文件

import SwiftUI import WebKitstruct ContentView: View {var body: some View {VStack {Text("测试")HTMLView(htmlFileName: "localfile") // 假设你的本地 HTML 文件名为 index.html.frame(minWidth: 100, minHeight: 100) // 设置 HTMLView 的最小尺寸…

【攻防世界】php_rce (ThinkPHP5)

进入题目环境&#xff0c;查看页面信息&#xff1a; 页面提示 ThinkPHP V5&#xff0c;猜测存在ThinkPHP5 版本框架的漏洞&#xff0c;于是查找 ThinkPHP5 的攻击POC。 构造 payload: http://61.147.171.105:50126/?sindex/think\app/invokefunction&functioncall_user_f…

续写Groq

这章写点Groq干货,理性的分析。 首先是Articical Analysis的关于Mixtral8*7B的吞吐比较 上图是有Mixtral 8*7BPaaS服务的AI服务商,Mistral自己居然排倒数第三 ,Groq是真的遥遥领先啊。 另外这个图是比较每100万tokens的cost,无论是推理速度还是cost,Groq都是遥遥领先…

如何把1G多的视频压缩到500兆以内?3个方法轻松减小文件内存~

微信已经成为了我们上班交流沟通时必不可少的通讯工具之一&#xff0c;在使用微信时&#xff0c;常常会遇到系统提示发送的word、ppt、pdf文件、视频、压缩包等文件超过1G&#xff0c;无法发送。有没有什么办法可以缩小文件的体积呢&#xff1f;今天给大家介绍几款可以用于视频…

Python中Python-docx 包的run介绍

先对run做一个简单地介绍。每个paragraph对象都包含一个run对象的列表。举例&#xff1a; 这是一个简短的段落。 from docx import Document doc Document("1.docx") #上面这段话保存在1.docx中 print("这一段的run个数是&#xff1a;",len(doc.paragr…

leetcode热题100.划分字母区间

Problem: 763. 划分字母区间 文章目录 题目思路复杂度Code 题目 给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段&#xff0c;同一字母最多出现在一个片段中。 注意&#xff0c;划分结果需要满足&#xff1a;将所有划分结果按顺序连接&#xff0c;得到的字符串仍…

基于Leaflet.js和Turf.js的等值线区间自定义及颜色自适应实践

目录 前言 一、Turf.js等值线相关制作 1、生成方法 2、主要参数 二、实际案例开发 1、新建展示页面 2、等值线生成 3、基于Leaflet的再优化 总结 前言 在气象方面的GIS应用当中&#xff0c;会根据实际的工作需要建立不同的监测站点。气象监测站的主要功能包括&#xff1…

如何快速识别陶瓷件的外观缺陷吗?

陶瓷件由陶瓷材料制成的物品或零部件&#xff0c;通常用于装饰、日常生活用品、工艺品或工业应用。陶瓷是一种非金属材料&#xff0c;具有耐高温、耐磨损、绝缘、化学稳定等特性&#xff0c;因此在许多领域得到广泛应用。 本案针对陶瓷件尺寸长25mm*宽11mm*高2mm的产品的外观检…

物联网实战--驱动篇之(五)TEA和AES加密算法

目录 一、前言 二、TEA算法 三、AES算法 四、加解密测试 五、安全性保障 一、前言 物联网的安全性是经常被提及的一个点&#xff0c;如果你的设备之间通讯没有加密的话&#xff0c;那么攻击者很容易就能获取并解析出报文的协议&#xff0c;从而根据攻击者的需要进行设备操…

运行gitHub中的vue项目,遇到三个报错解决方案

报错1&#xff1a;解决npm run serve启动报错npm ERR Missing script:"serve" 启动项目的时候用npm run serve发现报了以下的错误 npm ERR! Missing script: "serve" npm ERR! npm ERR! To see a list of scripts, run: npm ERR! npm runnpm ERR! A co…

Linux安装Oracle11g(无图形界面下的静默安装)

Oracle11g安装文档-Linux静默安装 环境准备安装数据库配置监听器创建数据库测试打开防火墙 环境准备 创建组和用户 [rootlocalhost ~]# groupadd oinstall #创建oinstall组 [rootlocalhost ~]# groupadd dba  #创建dba组 [rootlocalhost ~]# useradd -g oinstall -G dba -m…

window2003 中cmd提权到system

打开cmd&#xff0c;输入命令&#xff1a; sc Create syscm2 binPath "cmd /K start" type own type interact 注意&#xff01;等号左边是有空格然后才是引号的&#xff0c;三个等号都是&#xff0c;否则会失败 成功提示&#xff1a;[SC] CreateService 成功 然后…

Junit单元测试基础

目录 配置xml文件&#xff0c;注入依赖 常用注释 1.Test 2.BeforeAll和AfterAll 3.BeforeEach和AfterEach 4.TestMethodOrder 参数化 1.单参数 2.多参数 3.通过方法生成参数 测试用例执行管理 JUnit 是一个流行的 Java 单元测试框架&#xff0c;它为开发者提供了一…

题目 2694: 蓝桥杯2022年第十三届决赛真题-最大数字【暴力解法】

最大数字 原题链接 &#x1f970;提交结果 思路 对于每一位&#xff0c;我我们都要尽力到达 9 所以我们去遍历每一位, 如果是 9 直接跳过这一位 如果可以上调到 9 我们将这一位上调到 9 &#xff0c;并且在a 中减去对应的次数 同样的&#xff0c;如果可以下调到 9&#xff0c;我…

参数仅有0.049M!基于Mamba的医学图像分割新SOTA来了!

目前&#xff0c;基于CNN和Transformer的医学图像分割面临着许多挑战。比如CNN在长距离建模能力上存在不足&#xff0c;而Transformer则受到其二次计算复杂度的制约。 相比之下&#xff0c;Mamba的设计允许模型在保持线性计算复杂度的同时&#xff0c;仍然能够捕捉到长距离的依…

【AIGC】训练数据入库(Milvus)

之前的文章有写如何获取数据、如何补充数据&#xff0c;也有说如何对数据进行清洗、如何使用结构化数据进行训练。但好像没有说如何将训练数据“入库”。这里说的入库不是指 MySQL 数据库&#xff0c;而是指向量检索库 Milvus。 众所周知&#xff0c;人工智能多用向量数据进行…