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

news2024/11/15 21:54:19

文章目录

  • 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.coloradmin.cn/o/2144206.html

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

相关文章

【Python篇】NumPy完整指南(上篇):掌握数组、矩阵与高效计算的核心技巧

文章目录 Python NumPy学习指南第一部分&#xff1a;NumPy简介与安装1. 什么是NumPy&#xff1f;2. 安装NumPy使用pip安装&#xff1a;使用Anaconda安装&#xff1a; 第二部分&#xff1a;NumPy数组基础1. NumPy数组的创建从列表创建一维数组&#xff1a;创建多维数组&#xff…

发现了一个很神奇很哇塞的做事心态,就2个字

最近发现了一个很神奇很哇塞的做事心态&#xff0c;轻松收获了很多意向不到的结果&#xff0c;其实就两个字&#xff0c;会玩。 大家有没有发现&#xff0c;很多时候越是重要的地方&#xff0c;我们就会越用力&#xff0c;越用力的时候&#xff0c;反而结果却差强人意。越在意我…

IDC 2024未来企业大奖:酷克数据携手中国联通打造湖仓一体平台

9月11日-12日&#xff0c;2024 IDC中国年度峰会暨颁奖典礼于上海圆满召开。全球权威IT市场研究和咨询公司IDC公布了 2024 未来企业大奖的优秀奖名单。中国联通与酷克数据联合申报的《中国联通筑梦数字化转型&#xff1a;自主可控、开放协作的混合受管理湖仓一体平台》项目&…

Hi3516DV500 高清智慧视觉 SoC

1.1 概述 Hi3516DV500 是一颗面向视觉行业推出的高清智能 Soc 。该芯片最高支持 2 路 sensor 输入&#xff0c;支持最高 5M30fps 的 ISP 图像处理能力&#xff0c;支持 2F WDR 、多级降噪、六轴防 抖、多光谱融合等多种传统图像增强和处理算法&#xff0c;支持通…

企语iFair-协同管理系统-任意文件读取

文章目录 免责申明漏洞描述搜索语法漏洞复现yaml修复建议 免责申明 本文章仅供学习与交流&#xff0c;请勿用于非法用途&#xff0c;均由使用者本人负责&#xff0c;文章作者不为此承担任何责任 漏洞描述 企语iFair协同管理系统getuploadimage.jsp接口处存在任意文件读取漏洞…

发现抖音趋势与打造病毒内容的17种方法

无论是喜欢还是不喜欢&#xff0c;社交媒体总是关于什么是“流行”和受欢迎的。因此&#xff0c;毫不奇怪&#xff0c;随着TikTok的发展&#xff0c;TikTok的趋势也在不断增加。 TikTok趋势是指TikTok视频中具有吸引大量观众的特征。TikTok趋势通常始于一些通过尝试创意格式或…

算法知识点———并查集

并查集是一种用于管理元素所属集合的数据结构&#xff0c;实现为一个森林&#xff0c;其中每棵树表示一个集合&#xff0c;树中的节点表示对应集合中的元素。并查集支持两种操作&#xff1a; 合并&#xff08;Union&#xff09;&#xff1a;合并两个元素所属集合&#xff08;合…

第J4周:ResNet与DenseNet结合--DPN(pytorch版)

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营]中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊]** &#x1f4cc;本周任务&#xff1a;&#x1f4cc; ● 任务类型&#xff1a;自主探索⭐⭐ ● 任务难度&#xff1a;偏难 ●任务描…

nodejs 010:Webpack 可视化分析插件 webpack-bundle-analyzer的使用

安装 yarn add --dev webpack-bundle-analyzer 原始webpack.config.js 代码定义了 Webpack 的配置&#xff0c;主要任务是将 JavaScript 和 CSS 文件打包&#xff0c;并将 CSS 提取到单独的文件中&#xff0c;配置了对 Electron 应用的支持&#xff0c;同时还将 React 相关的…

Blue Screen of Death(BSOD)

Blue Screen of Death&#xff08;BSOD&#xff09;蓝屏 进来就是蓝屏。。。 按【电源】开关&#xff0c;连续三次 然后非常非常慢&#xff0c;启动了十几分钟 svchost (30028,R,98) TILEREPOSITORYS-1-5-18: 打开日志文件 C:\WINDOWS\system32\config\systemprofile\AppData…

6、定义字段状态变式

定义解释 字段状态变式是分配给公司代码的一项重要参数,在字段状态变式中罗列了很多字段状态组,而字段状态组是会计科目中的一个重要参数.它控制在输入一张会计记帐凭证时,该科目的那些辅助核算项目是必须输入的,哪些是不允许输入的,哪些是可以选择的 重点&#xff1a;科目组…

Adobe After Effects的插件--------Shatter 碎片

Shatter是AE的内置插件,其可模拟爆炸、破碎效果。 该效果将【效果图层】细化成一个个【碎片单体】,当爆破时这些【碎片单体】将被冲击,从【效果图层】上滑落。 视图 用不同的方式显示【效果图层】,以便调试。值有: 已渲染:显示【效果图层】的源图层线框正视图:只显示【…

SOCKS4和SOCKS5的区别是什么?

SOCKS4和SOCKS5是两种常用的网络代理协议&#xff0c;它们在功能、性能和应用场景上存在一些关键的区别。以下是对这两种协议区别的详细解析&#xff1a; 1. 支持的协议类型 SOCKS4&#xff1a;只支持TCP协议&#xff08;传输控制协议&#xff09;。这意味着SOCKS4代理只能用…

在vmvare安装飞牛私有云 fnOS体验教程

飞牛私有云&#xff08;fnOS&#xff09;是由飞牛网&#xff08;Feiniu&#xff09;开发的一款私有云操作系统&#xff0c;旨在为企业提供高效、安全、可扩展的云计算解决方案。 官网地址&#xff1a;https://www.fnnas.com/ 本章教程&#xff0c;主要介绍如何通过vmvare安装使…

Node.js 学习

目录 1.Node.js入门 1.1 什么是 Node.js 1.2 fs模块-读写文件 1.3 path模块-路径处理 1.4 案例-压缩前端html 1.5 认识URL中的端口号 1.6 http模块-创建Web服务 1.7 案例-浏览时钟 2.Node.js 模块化 2.1 模块化简介 2.1.1 什么是模块化&#xff1f; 2.1.2 CommonJS…

C++_类和对象(中、下篇)—— const成员函数、取地址运算符的重载、深入构造函数、类型转换、static成员、友元

目录 三、类和对象&#xff08;中&#xff09; 6、取地址运算符重载 1、const成员函数 2、取地址运算符的重载 四、类和对象&#xff08;下&#xff09; 1、深入构造函数 2、类型转换 3、static成员 4、友元 三、类和对象&#xff08;中&#xff09; 6、取地址运算…

从数据仓库到数据中台再到数据飞轮:我了解的数据技术进化史

这里写目录标题 前言数据仓库&#xff1a;数据整合的起点数据中台&#xff1a;数据共享的桥梁数据飞轮&#xff1a;业务与数据的双向驱动结语 前言 在当今这个数据驱动的时代&#xff0c;企业发展离不开对数据的深度挖掘和高效利用。从最初的数据仓库&#xff0c;到后来的数据…

docker可视化管理工具推荐!docker.ui

正式介绍之前&#xff0c;可以看下这款工具的截图&#xff0c;开源地址在文末提供&#xff1a; docker.ui&#xff1a;一个可视化的docker管理工具 docker是一个开源的容器平台&#xff0c;可以让开发者和运维人员快速地构建、运行和部署应用。 docker的优势在于它可以实现应…

Cpp类和对象(上)(3)

文章目录 前言一、面向过程与面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及类的封装类的访问限定符类的封装 五、类的作用域(类域)六、类的实例化七、类对象模型如何计算类对象的大小类对象的存储方式猜测 八、this指针this指针的引出this指针的特性 九、C语言…

dcmtk在MWLSCP会忽略对于字符集的匹配

版本信息 dcmtk v3.6.4 2018-11-29 发现的原因 在我将dcmtk的wlmscpfs当作MWLSCP使用的时候&#xff0c;我在SCU端为了防止过来的数据中存在不识别的字符集&#xff0c;对于收到的数据数据进行了字符集的过滤&#xff0c;但是发现过滤没有生效。 确保数据源 首先需要确认数…