C++设计模式(更新中)

文章目录

  • 1、创建型模式
    • 1.1 简单工厂(Simple Factory)
      • (1)示例
      • (2)总结
    • 1.2 工厂方法(Factory Method)
      • (1)示例
      • (2)总结
    • 1.3 抽象工厂(Abstract Factory)
      • (1)示例
      • (2)总结
    • 1.4 建造者(Builder)
      • (1)示例
      • (2)总结

1、创建型模式

1.1 简单工厂(Simple Factory)

简单工厂模式通过一个工厂类负责对象的创建,客户端只需提供参数,工厂类根据条件返回相应的对象。这种方式可以减少客户端对具体实现的依赖。

核心结构

  1. 工厂类:负责根据传入的参数生成具体对象。
  2. 产品抽象基类:定义所有产品的公共接口。
  3. 产品类:具体的实现类,继承自产品基类。
  4. 客户端:通过工厂类创建产品对象并调用其方法。
    在这里插入图片描述

(1)示例

假设正在开发一个工具库,工具种类包含绘制工具 (DrawTool) 和擦除工具 (EraseTool)。为了简化工具对象的创建和使用,可以通过简单工厂模式来生成这些工具。

库代码实现

  • 工具抽象类和具体工具类
    Tool.h:为了方便,这里没有分文件编写,实际中也可以分成Tool.h + Tool.cpp,工具太多也可以每个具体工具和工具接口类全部分开编写。之后的示例代码也是一样。

    #pragma once
    #include <iostream>// 工具基类
    class Tool
    {
    public:virtual void UseTool() = 0; virtual ~Tool() = default;
    };// 具体工具类1 - 绘制工具
    class DrawTool : public Tool
    {
    public:void UseTool() override{std::cout << "Using Draw Tool!" << std::endl;}
    };// 具体工具类2 - 擦除工具
    class EraseTool : public Tool
    {
    public:void UseTool() override{std::cout << "Using Erase Tool!" << std::endl;}
    };
    
  • 工厂类 (ToolFactory.hToolFactory.cpp)
    ToolFactory.h

    #pragma once
    #include <memory>
    #include "Tool.h"// 工厂类,用于创建工具对象
    class ToolFactory
    {
    public:enum class ToolType{Draw,Erase};// 简单工厂创建工具的静态方法static std::unique_ptr<Tool> CreateTool(ToolType type);
    };
    

    ToolFactory.cpp

    #include "ToolFactory.h"std::unique_ptr<Tool> ToolFactory::CreateTool(ToolType type)
    {switch (type){case ToolType::Draw:return std::make_unique<DrawTool>();case ToolType::Erase:return std::make_unique<EraseTool>();default:return nullptr;}
    }
    

使用者代码

使用者只需要引入 ToolFactory.h,通过工厂类创建工具对象,而不需要知道具体的工具类 DrawToolEraseTool。这减少了客户端和库中具体实现的依赖关系。

从下面代码,可以看到,实际上使用者这边还是需要依赖于工具基类的信息的(没有包含Tool.h是因为工厂类已经包含了),但是不需要知道具体的工具类的信息

Main.cpp

#include "ToolFactory.h" int main()
{// 使用工厂创建绘制工具std::unique_ptr<Tool> tool = ToolFactory::CreateTool(ToolFactory::ToolType::Draw);if (tool)tool->UseTool(); // 使用工厂创建擦除工具tool = ToolFactory::CreateTool(ToolFactory::ToolType::Erase);if (tool)tool->UseTool();return 0;
}

(2)总结

  • 优点:

    • 减少依赖:客户端只需依赖工厂类与产品基类,而不需要依赖具体产品类。
    • 解耦创建与使用:工厂类封装了创建细节,客户端只负责使用产品。
  • 缺点:

    • 违反开闭原则:每次添加新的工具类型,必须修改工厂类的 CreateTool 方法,添加一条新的case:,导致不符合 “对修改关闭,对扩展开放”的原则。在扩展性和代码维护上有一定的缺点,特别是在需要频繁添加新工具类型的情况下。
    • 工厂类复杂化:工厂类会随产品种类的增加而变得复杂。

1.2 工厂方法(Factory Method)

工厂方法模式通过将创建对象的逻辑推迟到子类中,从而解决简单工厂模式违反开闭原则的问题。它的核心理念是将工厂类拆分成多个具体工厂,每个工厂类负责创建某种特定产品。

核心结构

抽象产品 + 具体产品,抽象工厂 + 具体工厂
在这里插入图片描述

(1)示例

重构1.1中的示例代码,工具基类及其子类保持不变,但工厂类需要改造成每种产品对应一个工厂子类,各自负责产品的创建。

  • 工厂类ToolFactory.h
    #pragma once
    #include <memory>
    #include "Tool.h"class ToolFactory 
    {
    public:virtual std::unique_ptr<Tool> CreateTool() = 0;virtual ~ToolFactory() = default;
    };class DrawToolFactory : public ToolFactory 
    {
    public:std::unique_ptr<Tool> CreateTool() override {return std::make_unique<DrawTool>();}
    };class EraseToolFactory : public ToolFactory 
    {
    public:std::unique_ptr<Tool> CreateTool() override {return std::make_unique<EraseTool>();}
    };
    
  • 客户端使用main.cpp
    #include "ToolFactory.h"int main()
    {// 创建绘制工具工厂对象std::unique_ptr<ToolFactory> drawFactory = std::make_unique<DrawToolFactory>();// 创建绘制工具std::unique_ptr<Tool> drawTool = drawFactory->CreateTool();if (drawTool)drawTool->UseTool();// 创建擦除工具工厂对象std::unique_ptr<ToolFactory> eraseFactory = std::make_unique<EraseToolFactory>();// 创建擦除工具std::unique_ptr<Tool> eraseTool = eraseFactory->CreateTool();if (eraseTool)eraseTool->UseTool();return 0;
    }
    

(2)总结

  • 优点

    • 符合开闭原则:新增产品时,只需新增对应的工厂类,而无需修改已有代码。
    • 单一职责:每个工厂类只负责创建一种产品,职责更为明确。
    • 可扩展性:更方便地增加新产品和新工厂,且代码修改局部化,减少潜在错误。
  • 缺点

    • 类的增加:每种产品都需要对应的工厂类,会导致类的数量增加,增加系统的复杂性。
    • 复杂度提升:对于简单的对象创建场景,工厂方法模式可能显得过于复杂,因为每个具体产品都需要单独的工厂类。
    • 职责分散:每个工厂类只负责创建某种具体产品,可能导致系统中存在较多分散的创建逻辑,维护起来可能不便。

1.3 抽象工厂(Abstract Factory)

在某些情况下,我们需要创建一组相关或依赖的对象,而不仅仅是单个对象。工厂方法模式虽然可以创建单个产品,但如果需要创建多个产品,并且这些产品之间存在某种强关联(比如 UI 系统中不同平台的按钮、文本框等,比如windows平台的按钮必须搭配同平台的文本框),工厂方法模式就显得不足了。

抽象工厂模式提供一个接口,用于创建相关联的对象族,而不指定它们的具体类。它解决了创建多类相关产品的问题,而不是单个产品。

核心结构:

  1. 抽象工厂类:定义创建一系列相关产品的接口。
  2. 具体工厂类:实现抽象工厂的接口,负责创建一系列具体产品。
  3. 抽象产品类:为不同产品提供统一的接口。
  4. 具体产品类:每个具体工厂创建的不同产品实现类。
  5. 客户端:通过抽象工厂接口来获取相关联的产品。
    在这里插入图片描述

(1)示例

假设现在有4种具体工具产品,分别是2D绘制工具、2D擦除工具、3D绘制工具、3D擦除工具,正常情况来说,2D绘制工具跟2D擦除工具肯定是配套的,如果工厂方法来创建,就可能混淆使用,而抽象工厂则可以避免这种错误产生

  • Tool.h:这里从Tool接口类直接派生了4个工具,也可以这样做(根据需求灵活处理):

    • 定义2DTool抽象类和3DTool抽象类,然后再分别派生2个具体工具类出来
    • 定义DrawTool抽象类和EraseTool抽象类,然后再分别派生2个具体工具类出来
    #pragma once
    #include <iostream>// 抽象产品类 - 工具
    class Tool 
    {
    public:virtual void UseTool() = 0;virtual ~Tool() = default;
    };// 具体产品类 - 2D绘制工具
    class Draw2DTool : public Tool 
    {
    public:void UseTool() override {std::cout << "Using 2D Draw Tool!" << std::endl;}
    };// 具体产品类 - 2D擦除工具
    class Erase2DTool : public Tool 
    {
    public:void UseTool() override {std::cout << "Using 2D Erase Tool!" << std::endl;}
    };// 具体产品类 - 3D绘制工具
    class Draw3DTool : public Tool 
    {
    public:void UseTool() override {std::cout << "Using 3D Draw Tool!" << std::endl;}
    };// 具体产品类 - 3D擦除工具
    class Erase3DTool : public Tool 
    {
    public:void UseTool() override {std::cout << "Using 3D Erase Tool!" << std::endl;}
    };
    
  • Factory.h

    #pragma once
    #include <memory>
    #include "Tool.h"// 抽象工厂类
    class ToolFactory 
    {
    public:virtual std::unique_ptr<Tool> CreateDrawTool() = 0;virtual std::unique_ptr<Tool> CreateEraseTool() = 0;virtual ~ToolFactory() = default;
    };// 具体工厂类 - 2D工具工厂
    class Tool2DFactory : public ToolFactory 
    {
    public:std::unique_ptr<Tool> CreateDrawTool() override {return std::make_unique<Draw2DTool>();}std::unique_ptr<Tool> CreateEraseTool() override {return std::make_unique<Erase2DTool>();}
    };// 具体工厂类 - 3D工具工厂
    class Tool3DFactory : public ToolFactory 
    {
    public:std::unique_ptr<Tool> CreateDrawTool() override {return std::make_unique<Draw3DTool>();}std::unique_ptr<Tool> CreateEraseTool() override {return std::make_unique<Erase3DTool>();}
    };
    
  • main.cpp

    // Main.cpp
    #include "Factory.h"int main() {// 创建2D工厂std::unique_ptr<ToolFactory> factory2D = std::make_unique<Tool2DFactory>();std::unique_ptr<Tool> tool = factory2D->CreateDrawTool();tool->UseTool(); tool = factory2D->CreateEraseTool();tool->UseTool(); // 创建3D工厂std::unique_ptr<ToolFactory> factory3D = std::make_unique<Tool3DFactory>();tool = factory3D->CreateDrawTool();tool->UseTool();  tool = factory3D->CreateEraseTool();tool->UseTool(); return 0;
    }
    

(2)总结

  • 优点

    • 产品族一致性:通过具体工厂类,确保了 2D 和 3D 工具的内部一致性,避免在客户端中创建不兼容的工具(如混用 2D 和 3D 工具)。
    • 在新增工具方面,遵守开闭原则:新增其他绘制工具类型时,比如一个4D工具,只需额外实现新的具体工厂类和对应的产品类,保证了系统的可扩展性。
    • 减少客户端依赖:客户端只依赖抽象工厂和抽象产品,而不需要关心具体实现的细节,符合依赖倒置原则。
  • 缺点

    • 复杂性:增加了工厂类和产品类的数量,系统结构更加复杂,尤其当产品族多时会造成一定的维护压力。
    • 在新增每种工具的功能时,不遵守开闭原则:比如现在的每种工具套件都支持绘制、擦除工具,我还想新增一个修改工具,则需要修改每一个工厂类和每一个产品类的代码。
    • 灵活性降低:所有工厂创建的产品都是预定义的,无法灵活组合不同种类的产品。

1.4 建造者(Builder)

建造者模式的作用是将复杂对象的组装过程和对象的实际表示区分开来。这样,相同的组装步骤可以用来制造出不同的对象表现形式。这种模式非常适合于那些由多个可选组件组成的复杂对象。通过分步骤地构建每个组件,我们可以根据需要灵活地组合出各种不同的对象。

建造者模式的核心理念是通过引入一个建造者(Builder)类,负责构建对象的各个部分,而不是在一个复杂的构造函数中完成所有工作。它能够分阶段创建对象,允许客户端在构建过程中灵活选择和配置对象的组件。该模式还允许通过实现不同的具体建造者,来生成不同类型或版本的产品对象。

直接上具体案例,来理解这个模式

(1)示例

组装电脑,电脑有很多可定制的部件(如CPU、GPU、硬盘、内存等),对于不同的需求(比如游戏电脑、办公电脑),需要选用不同的性能、品牌的部件,建造者模式可以灵活地应对这些变化。

在这里插入图片描述
类之间的关系

  1. Director:通过 Builder 来控制建造流程,确保每个步骤按顺序调用。它不需要知道具体的产品细节,只需要负责调用 Builder 提供的接口。
  2. Builder:定义了构建的接口,具体的建造步骤(如 BuildCPU()BuildGPU() 等)。
  3. ConcreteBuilder:实现 Builder 接口的具体类,负责创建不同类型的产品,如游戏电脑和办公电脑。每个 ConcreteBuilder 实现了相同的建造步骤,但生成不同的结果。
  4. Product:是最终生成的对象,它包含了多个部分(CPU、GPU、Memory 等),由 ConcreteBuilder 一步步构建。
#include <iostream>
#include <string>// 产品类:电脑
class Computer 
{
public:void SetCPU(const std::string& cpu) { CPU = cpu; }void SetGPU(const std::string& gpu) { GPU = gpu; }void SetMemory(const std::string& memory) { Memory = memory; }void SetStorage(const std::string& storage) { Storage = storage; }void ShowSpecifications() const {std::cout << "Computer Specifications:\n";std::cout << "CPU: " << CPU << "\n";std::cout << "GPU: " << GPU << "\n";std::cout << "Memory: " << Memory << "\n";std::cout << "Storage: " << Storage << "\n";}private:std::string CPU;std::string GPU;std::string Memory;std::string Storage;
};// 抽象建造者:定义创建产品的步骤
class ComputerBuilder 
{
public:virtual ~ComputerBuilder() = default;virtual void BuildCPU() = 0;virtual void BuildGPU() = 0;virtual void BuildMemory() = 0;virtual void BuildStorage() = 0;virtual Computer* GetResult() = 0;
};// 具体建造者:游戏电脑
class GamingComputerBuilder : public ComputerBuilder 
{
private:Computer* computer;public:GamingComputerBuilder() {computer = new Computer();}~GamingComputerBuilder() {delete computer;}void BuildCPU() override {computer->SetCPU("i9");}void BuildGPU() override {computer->SetGPU("RTX4090 ");}void BuildMemory() override {computer->SetMemory("16GB DDR4");}void BuildStorage() override {computer->SetStorage("1TB SSD");}Computer* GetResult() override {return computer;}
};// 具体建造者:办公电脑
class OfficeComputerBuilder : public ComputerBuilder 
{
private:Computer* computer;public:OfficeComputerBuilder() {computer = new Computer();}~OfficeComputerBuilder() {delete computer;}void BuildCPU() override {computer->SetCPU("i3");}void BuildGPU() override {computer->SetGPU("GTX 960");}void BuildMemory() override {computer->SetMemory("8GB DDR4");}void BuildStorage() override {computer->SetStorage("512GB SSD");}Computer* GetResult() override {return computer;}
};// 指挥者:控制建造流程
class Director 
{
private:ComputerBuilder* builder = nullptr;
public:void SetBuilder(ComputerBuilder* builder) {this->builder = builder;}void Construct() {builder->BuildCPU();builder->BuildGPU();builder->BuildMemory();builder->BuildStorage();}
};// 客户端代码
int main() 
{Director director;// 创建游戏电脑GamingComputerBuilder gamingBuilder;director.SetBuilder(&gamingBuilder);director.Construct();Computer* gamingComputer = gamingBuilder.GetResult();gamingComputer->ShowSpecifications();// 创建办公电脑OfficeComputerBuilder officeBuilder;director.SetBuilder(&officeBuilder);director.Construct();Computer* officeComputer = officeBuilder.GetResult();officeComputer->ShowSpecifications();delete gamingComputer;delete officeComputer;return 0;
}

(2)总结

  • 优点:

    • 灵活应对不同需求:在这个例子中,游戏电脑和办公电脑虽然都是由CPU、GPU、内存和硬盘等部件组成,但具体的配置差别很大。通过 Director 控制构建顺序,我们可以复用建造流程,但根据不同的 具体ConcreteBuilder 实现来生成不同的产品。这使得我们在不修改整体构建逻辑的情况下,可以灵活地创建多种不同的对象。

    • 易扩展:建造者模式将复杂对象的构建过程与具体的构建实现解耦。Director 只需要知道如何控制创建流程,具体怎么创建、用什么配置并不重要。通过这种解耦,可以很容易地替换或扩展新的 ConcreteBuilder,比如还可以再实现一个 WorkstationComputerBuilder,用于构建工作站电脑。

    • 代码更加清晰:对于复杂对象的构建,通过一步步调用建造方法(如 BuildCPU()BuildMemory()),构建过程非常清晰易懂。这种模式避免了构建过程中混乱的条件判断和冗长的构造代码。

  • 缺点:

    • 增加代码复杂度:模式引入了额外的建造者、指导者等类,可能会使代码量增多,结构变复杂。
    • 多次构建成本高:如果每次构建都需要重建所有对象部分,可能导致性能开销。

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

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

相关文章

Sass实现文字两侧横线及Sass常用方案

Sass常用方案及Sass实现文字两侧横线 1.Sass实现文字两侧横线2.用Sass简化媒体查询3.使用继承占位符实现样式复用4.Sass 模块化5.lighten 和 darken 自我记录 1.Sass实现文字两侧横线 mixin 的基本作用&#xff1a; 代码复用&#xff1a;把常用的样式封装在一起&#xff0c;…

SpringCloud-04 OpenFeign服务调用与负载均衡

OpenFeign是一个声明式、模板化的HTTP客户端&#xff0c;它简化了在Java应用程序中调用RESTful API的过程。OpenFeign是Netflix开发的一个开源项目&#xff0c;它构建在Feign的基础上&#xff0c;为开发者提供了更加简单、灵活的方式来实现HTTP请求。OpenFeign的特点包括&#…

地平线秋招2025

【地平线秋招】 中秋卷起来&#xff01;&#xff01;&#xff01; 内推码 kbrfck 内推码 kbrfck 内推码 kbrfck 投递链接&#xff1a;https://wecruit.hotjob.cn/SU62d915040dcad43c775ec12c/mc/position/campus?acotycoCodekbrfck&recruitType1&isLimitShowPostScope…

【Google Chrome Windows 64 version及 WebDriver 版本】

最近升级到最新版本Chrome后发现页面居然显示错乱实在无语, 打算退回原来的版本, 又发现官方只提供最新的版本下载, 为了解决这个问题所有收集了Chrome历史版本的下载地址分享给大家. Google Chrome Windows version 64 位 VersionSize下载地址Date104.0.5112.10282.76 MBhtt…

STL相关简介

string 看到这个词&#xff0c;相信大家一定都很好奇什么是string&#xff0c;它有什么作用呢&#xff1f;今天&#xff0c;就让我们一起来了解一下关于string的简介吧~ 目录 string 1. 什么是STL 2. STL的版本 3. STL的六大组件 4. STL的重要性 5. 如何学习STL 6.STL的…

Unity实战案例全解析 :PVZ 植物脚本分析

植物都继承了Pants脚本&#xff0c;但是我因为没注意听讲&#xff0c;把Pants也挂在植物上了&#xff0c;所以子类的PlantEnableUpdate和PlantDisableUpdate抢不过父类&#xff0c;无法正确触发动画&#xff0c;我还找不到哪里出了问题&#xff0c;所以就使用了携程加while强行…

bpf的了解以及bpftrace的简单练习

最近接触到bpf的概念&#xff0c;简单做一些练习&#xff0c;做以下整理&#xff0c;学习笔记。 0&#xff1a;总结 使用ebpf可以实现的功能打开新世界&#xff0c;可以不改变源码的情况下&#xff0c;实现内存&#xff0c;网络&#xff0c;对应接口等各种期望内容的监控。 …

王者荣耀改重复名(java源码)

王者荣耀改重复名 项目简介 “王者荣耀改重复名”是一个基于 Spring Boot 的应用程序&#xff0c;用于生成王者荣耀游戏中的唯一名称。通过简单的接口和前端页面&#xff0c;用户可以输入旧名称并获得一个新的、不重复的名称。 功能特点 生成新名称&#xff1a;提供一个接口…

C++基础知识7 list

list 1. list的介绍及使用1.1 list的介绍1.2 list的使用1.2.1 list的构造1.2.2 list iterator的使用1.2.3 list capacity1.2.4 list element access1.2.5 list modifiers1.2.6 list的迭代器失效 2.1 模拟实现list 1. list的介绍及使用 1.1 list的介绍 1.2 list的使用 1.2.1 l…

aspcms 获取webshell漏洞复现

1.通过访问/admin_aspcms/login.asp来到后台 使用admin 123456 登录 2.点击扩展功能-幻灯片设置-保存&#xff0c;同时进行抓包 3.修改数据包中的slideTextStatus字段&#xff0c;将其更改为 1%25><%25Eval(Request (chr(65)))%25><%25 密码为a 4.访问木马的地…

面试官:讲一讲Spring MVC源码解析

好看的皮囊千篇一律、有趣的灵魂万里挑一 文章持续更新&#xff0c;可以微信搜索【小奇JAVA面试】第一时间阅读&#xff0c;回复【资料】获取福利&#xff0c;回复【项目】获取项目源码&#xff0c;回复【简历模板】获取简历模板&#xff0c;回复【学习路线图】获取学习路线图。…

wopop靶场漏洞挖掘练习

1、SQL注入漏洞 1、在搜索框输入-1 union select 1,2,3# 2、输入-1 union select 1,2,database()# &#xff0c;可以得出数据库名 3、输入-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schematest#&#xff0c;可以得出数据库中…

C++ | Leetcode C++题解之第405题数字转换为十六进制数

题目&#xff1a; 题解&#xff1a; class Solution { public:string toHex(int num) {if (num 0) {return "0";}string sb;for (int i 7; i > 0; i --) {int val (num >> (4 * i)) & 0xf;if (sb.length() > 0 || val > 0) {char digit val …

JDBC实现对单表数据增、删、改、查

文章目录 API介绍获取 Statement 对象Statement的API介绍使用步骤案例代码 JDBC实现对单表数据查询ResultSet的原理ResultSet获取数据的API使用JDBC查询数据库中的数据的步骤案例代码 API介绍 获取 Statement 对象 在java.sql.Connection接口中有如下方法获取到Statement对象…

汽车电子笔记之-013:旋变硬解码ADI芯片AD2S1210使用记录(从零开始到软件实现)

目录 1、概述 2、技术规格 3、芯片引脚 4、旋变信号格式 5、使用过程只是要点分析 5.1、程序注意点分析 5.1.1、SPI配置时序 5.1.2、问题一&#xff1a;SPI时序问题 5.1.3、问题二&#xff1a;SPI读取时序&#xff08;配置模式&#xff09; 5.1.4、问题三&#xff1a…

削峰+限流:秒杀场景下的高并发写请求解决方案

我是小米,一个喜欢分享技术的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货! 哈喽,大家好!我是小米,一个29岁、活泼积极、热衷分享技术的码农。今天和大家聊一聊应对高并发的写请求这个主题,尤其是在大促、秒杀这种场景下,系统…

非线性规划及其MATLAB实现

目录 引言 非线性规划的基本模型 非线性规划的求解方法 非线性规划的MATLAB实现 例子&#xff1a;多目标优化问题的非线性规划求解 表格总结&#xff1a;MATLAB常用非线性规划函数 实例&#xff1a;使用MATLAB求解非线性投资决策问题 结论 引言 非线性规划&#xff08;…

ES6解构赋值详解;全面掌握:JavaScript解构赋值的终极指南

目录 全面掌握&#xff1a;JavaScript解构赋值的终极指南 一、数组解构赋值 1、基本用法 2、跳过元素 3、剩余元素 4、默认值 二、对象解构赋值 1、基本用法 2、变量重命名 3、默认值 4、嵌套解构 三、复杂的嵌套结构解构 四、函数参数解构赋值 1、对象解构作为函…

C/C++实现植物大战僵尸(PVZ)(打地鼠版)

&#x1f680;欢迎互三&#x1f449;&#xff1a;程序猿方梓燚 &#x1f48e;&#x1f48e; &#x1f680;关注博主&#xff0c;后期持续更新系列文章 &#x1f680;如果有错误感谢请大家批评指出&#xff0c;及时修改 &#x1f680;感谢大家点赞&#x1f44d;收藏⭐评论✍ 游戏…

2022高教社杯全国大学生数学建模竞赛C题 问题一(1) Python代码演示

目录 问题 11.1 对这些玻璃文物的表面风化与其玻璃类型、纹饰和颜色的关系进行分析数据探索 -- 单个分类变量的绘图树形图条形图扇形图雷达图Cramer’s V 相关分析统计检验列联表分析卡方检验Fisher检验绘图堆积条形图分组条形图分类模型Logistic回归随机森林import matplotlib…