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

突破编程_C++_设计模式(组合模式)

1 组合模式的基本概念

C++中的组合模式是一种对象结构型模式,它将多个对象组合成树形结构,以表示具有整体-部分关系的层次结构。在这个模式中,对单个对象(叶子对象)与组合对象(容器对象)的使用具有一致性,因此组合模式又称为部分-整体模式。

组合模式的主要概念包括:

(1)抽象组件(Component): 这是组合模式中最重要的接口或抽象类,它声明了访问及管理子组件的方法,如增加子组件、删除子组件、获取子组件等。所有叶子组件和容器组件都应当实现这个接口。

(2)叶子组件(Leaf): 这是组合模式中的基本对象,它实现了抽象组件中定义的行为,并且没有子组件。

(3)容器组件(Composite): 这是包含子组件的组合对象,它可以包含叶子组件和其他容器组件,形成一个树形结构。容器组件实现了抽象组件中定义的行为,并提供了管理和操作其子组件的方法。

使用组合模式的主要优点在于,客户端可以一致地处理单个对象和组合对象,无需关心它们之间的具体差异。这使得代码更加简洁、清晰,并提高了系统的灵活性和可维护性。

组合模式在多种场景中都非常有用,例如当需要表示具有整体与部分关系的层次结构时,或者当希望忽略整体与部分的差异,以一种统一的方式处理它们时。此外,当系统中需要处理树形结构,或者需要动态地增加新的类型时,组合模式也是一个很好的选择。

2 组合模式的实现步骤

组合模式的实现步骤如下:

(1)定义抽象组件(Component)接口:
创建一个抽象类或接口,表示组件的通用行为。
在该接口中,定义用于操作组件的方法,比如添加、删除子组件,获取子组件等。

(2)实现叶子组件(Leaf)类:
创建一个或多个叶子组件类,继承或实现抽象组件接口。
在叶子组件类中,实现抽象组件接口中定义的方法,但通常叶子组件不会有子组件,所以添加和删除子组件的方法可能会抛出异常或执行空操作。

(3)实现容器组件(Composite)类:
创建一个容器组件类,继承或实现抽象组件接口。
在容器组件类中,除了实现抽象组件接口中定义的方法外,还需要维护一个子组件列表。
提供方法来添加、删除和获取子组件,并可以递归地调用子组件的相应方法。

(4)组合组件:
在客户端代码中,可以创建叶子组件和容器组件的实例,并将它们组合起来形成树形结构。
客户端可以通过容器组件的接口来操作整个树形结构,无论是访问叶子组件还是递归地操作子树。

如下为样例代码:

#include <iostream>  
#include <vector>  
#include <string>  
#include <memory>  
#include <algorithm>  // 定义抽象组件(Component)接口  
class Component {
public:virtual ~Component() {}virtual void operation() const = 0;virtual void add(std::shared_ptr<Component> component) = 0;virtual void remove(Component* component) = 0;virtual Component* getChild(int index) = 0;virtual int getNumChildren() const = 0;virtual bool isComposite() const = 0;virtual bool isLeaf() const = 0;
};// 实现叶子组件(Leaf)类  
class Leaf : public Component {
public:Leaf(const std::string& name) : m_name(name) {}void operation() const override {std::cout << "Leaf operation: " << m_name << std::endl;}void add(std::shared_ptr<Component> component) override {std::cout << "Leaf cannot have children." << std::endl;}void remove(Component* component) override {std::cout << "Leaf cannot remove children." << std::endl;}Component* getChild(int index) override {return nullptr;}int getNumChildren() const override {return 0;}bool isComposite() const override {return false;}bool isLeaf() const override {return true;}private:std::string m_name;
};// 实现容器组件(Composite)类  
class Composite : public Component {
public:Composite(const std::string& name) : m_name(name) {}void operation() const override {std::cout << "Composite operation: " << m_name << std::endl;for (const auto& child : m_children) {child->operation();}}void add(std::shared_ptr<Component> component) override {m_children.push_back(std::move(component));}void remove(Component* component) override {auto it = std::find_if(m_children.begin(), m_children.end(),[component](const std::shared_ptr<Component>& c) {return c.get() == component;});if (it != m_children.end()) {m_children.erase(it);}else {std::cout << "Component not found in children." << std::endl;}}Component* getChild(int index) override {if (index < 0 || index >= m_children.size()) {return nullptr;}return m_children[index].get();}int getNumChildren() const override {return m_children.size();}bool isComposite() const override {return true;}bool isLeaf() const override {return false;}private:std::string m_name;std::vector<std::shared_ptr<Component>> m_children;
};// 组合组件  
int main() 
{// 创建叶子组件和容器组件实例  std::shared_ptr<Leaf> leaf1 = std::make_shared<Leaf>("Leaf1");std::shared_ptr<Leaf> leaf2 = std::make_shared<Leaf>("Leaf2");std::shared_ptr<Composite> composite = std::make_shared<Composite>("Composite");// 将叶子组件添加到容器组件中  composite->add(std::move(leaf1));composite->add(std::move(leaf2));// 执行操作  composite->operation();// 移除组件(如果需要)  // composite->remove(leaf1.get());  return 0;
}

上面代码的输出为:

Composite operation: Composite
Leaf operation: Leaf1
Leaf operation: Leaf2

在这个示例中,定义了一个 Component 抽象类,它包含了组件的通用行为。Leaf 类表示叶子组件,它实现了 Component 接口,但通常不会有子组件。Composite 类表示容器组件,它同样实现了 Component 接口,并维护了一个子组件列表。

这个示例展示了组合模式的基本结构和使用方式。可以根据需要扩展这个示例,添加更多的组件类型、方法或操作,以适应具体应用场景。

3 组合模式的应用场景

C++ 中的组合模式应用场景主要涉及到需要表示对象的整体-部分层次结构,并希望客户端能够以统一的方式处理单个对象和对象组合的情况。以下是一些具体的应用场景:

(1)文件系统: 文件系统中的文件和文件夹是典型的组合模式应用场景。文件夹可以包含文件和其他文件夹,形成树形结构。通过组合模式,用户可以统一地处理文件和文件夹,如进行遍历、搜索、删除等操作,而无需区分它们的具体类型。

(2)图形用户界面(GUI): 在GUI中,窗口、面板、按钮、文本框等组件经常需要组合使用。组合模式允许将这些组件组织成树形结构,使得用户可以通过统一的接口来管理和操作这些组件。例如,一个窗口可以包含多个面板,而面板又可以包含按钮和文本框等子组件。

(3)菜单系统: 在复杂的菜单系统中,菜单项可能包含子菜单,形成多级菜单结构。通过组合模式,可以方便地管理这种多级菜单,并允许用户通过统一的接口进行导航和操作。

(4)部门组织架构: 在企业或组织的部门结构中,部门可能包含子部门或员工,形成层次化的组织结构。组合模式可以用于表示这种组织结构,并允许管理层以统一的方式管理和查询各个部门或员工的信息。

在这些应用场景中,组合模式使得客户端代码更加简洁和清晰,因为客户端只需要与抽象组件接口进行交互,而无需关心具体是处理单个对象还是对象组合。此外,组合模式还具有良好的扩展性,可以方便地添加新的组件类型或修改现有组件的行为,而无需修改客户端代码。

3.1 组合模式应用于文件系统

C++ 组合模式应用于文件系统的示例可以描述如下:

首先,定义一个 FileSystemElement 抽象类,它表示文件系统中的元素,可以是文件或文件夹。这个类将声明一些基本的操作,如名称的获取和设置。

#include <iostream>  
#include <string>  
#include <vector>  
#include <memory>  class FileSystemElement {
public:virtual ~FileSystemElement() {}virtual std::string getName() const = 0;virtual void setName(const std::string& name) = 0;// 可能还有其他通用操作,如访问权限设置等  
};

然后,实现 File 类,表示文件系统中的一个文件。它继承自 FileSystemElement,并实现其中的方法。

class File : public FileSystemElement {
public:File(const std::string& name) : name(name) {}std::string getName() const override {return name;}void setName(const std::string& name) override {this->name = name;}// 文件特有的操作,如读取内容、写入内容等 private:std::string name;
};

接下来,实现 Directory 类,表示文件系统中的一个文件夹。它也继承自 FileSystemElement,并实现其中的方法。此外,它还需要维护一个包含子元素的列表。

class Directory : public FileSystemElement {
public:Directory(const std::string& name) : name(name) {}std::string getName() const override {return name;}void setName(const std::string& name) override {this->name = name;}void addChild(std::shared_ptr<FileSystemElement> child) {children.push_back(child);}// 文件夹特有的操作,如遍历子元素、删除子元素等  void traverse() const {for (const auto& child : children) {std::cout << child->getName() << std::endl;if (auto dir = dynamic_cast<const Directory*>(child.get())) {dir->traverse(); // 递归遍历子文件夹  }}}private:std::string name;std::vector<std::shared_ptr<FileSystemElement>> children;
};

现在,可以使用这些类来构建文件系统树:

int main() 
{// 创建文件夹和文件对象  std::shared_ptr<Directory> root = std::make_shared<Directory>("root");std::shared_ptr<Directory> dir1 = std::make_shared<Directory>("dir1");std::shared_ptr<File> file1 = std::make_shared<File>("file1.txt");std::shared_ptr<File> file2 = std::make_shared<File>("file2.txt");// 将文件和文件夹添加到树中  root->addChild(dir1);dir1->addChild(file1);dir1->addChild(file2);// 遍历并打印文件系统树的内容  root->traverse();return 0;
}

上面这些代码的输出为:

dir1
file1.txt
file2.txt

这个简单的示例展示了如何使用组合模式来构建一个文件系统的树形结构,并允许通过统一的方式处理文件和文件夹。在实际应用中,文件系统通常会有更多的操作和功能,如文件的读写、权限管理、路径解析等,但这些都可以基于这个基本框架进行扩展。

3.2 组合模式应用于图形用户界面(GUI)

C++ 组合模式应用于图形用户界面(GUI)的示例可以描述如下:

首先,定义一个 GUIComponent 抽象类,它表示 GUI 中的一个组件。这个类将声明一些基本的操作,如绘制、添加子组件等。

#include <iostream>  
#include <vector>  
#include <memory>   
#include <string>   
#include <algorithm> class GUIComponent {
public:virtual ~GUIComponent() {}virtual void draw() const = 0;virtual void add(std::shared_ptr<GUIComponent> component) = 0;virtual void remove(GUIComponent* component) = 0;// 可能还有其他通用操作,如设置位置、大小等  
};

然后,实现 LeafComponent 类,表示 GUI 中的一个叶子组件,比如一个按钮或文本框。它继承自 GUIComponent,并实现其中的方法。

class LeafComponent : public GUIComponent {
public:LeafComponent(const std::string& name) : name(name) {}void draw() const override {std::cout << "Drawing leaf component: " << name << std::endl;}void add(std::shared_ptr<GUIComponent> component) override {// 叶子组件不能添加子组件,可以抛出异常或忽略  std::cout << "Leaf component cannot add child components." << std::endl;}void remove(GUIComponent* component) override {// 叶子组件没有子组件可移除,可以抛出异常或忽略  std::cout << "Leaf component has no child components to remove." << std::endl;}private:std::string name;
};

接下来,实现 CompositeComponent 类,表示 GUI 中的一个容器组件,比如一个窗口或面板。它也继承自 GUIComponent,并实现其中的方法。此外,它还需要维护一个包含子组件的列表。

class CompositeComponent : public GUIComponent {
public:CompositeComponent(const std::string& name) : name(name) {}void draw() const override {std::cout << "Drawing composite component: " << name << std::endl;for (const auto& child : children) {child->draw(); // 递归绘制子组件  }}void add(std::shared_ptr<GUIComponent> component) override {children.push_back(std::move(component));}void remove(GUIComponent* component) override {auto it = std::find_if(children.begin(), children.end(),[component](const std::shared_ptr<GUIComponent>& c) {return c.get() == component;});if (it != children.end()) {children.erase(it);}else {std::cout << "Component not found in children." << std::endl;}}private:std::string name;std::vector<std::shared_ptr<GUIComponent>> children;
};

现在,可以使用这些类来构建GUI:

int main() 
{// 创建叶子组件和容器组件对象  std::shared_ptr<LeafComponent> button = std::make_shared<LeafComponent>("Button");std::shared_ptr<LeafComponent> textBox = std::make_shared<LeafComponent>("TextBox");std::shared_ptr<CompositeComponent> window = std::make_shared<CompositeComponent>("Window");// 将叶子组件添加到容器组件中  window->add(button);window->add(textBox);// 绘制GUI  window->draw();// 移除组件(如果需要)  // window->remove(button.get()); // 假设想要移除按钮  return 0;
}

上面这些代码的输出为:

Drawing composite component: Window
Drawing leaf component: Button
Drawing leaf component: TextBox

这个简单的示例展示了如何使用组合模式来构建一个GUI,并允许通过统一的方式处理容器组件和叶子组件。在实际应用中,GUI组件通常会有更多的属性和方法,比如处理用户事件、更新状态等,但这些都可以基于这个基本框架进行扩展。

4 组合模式的优点与缺点

C++ 组合模式的优点主要包括:

(1)结构清晰: 组合模式可以清晰地定义分层次的复杂对象,表示对象的全部或部分层次,使得客户端能够忽略对象组合和单个对象的区别,一致地对待组合结构中的所有对象。这有助于简化客户端代码,提高代码的可读性和可维护性。

(2)扩展性好: 在组合模式中,增加新的容器构件和叶子构件都很方便,无需对现有类库进行任何修改,这符合“开闭原则”。这使得系统的扩展和修改变得更加容易,降低了系统的耦合度。

(3)灵活性高: 组合模式可以灵活地将不同的叶子节点抽象成相同的节点,达成忽略整体-部分差异的目标,最终给用户的是统一的抽象接口。这使得系统能够更灵活地应对各种复杂情况,提高了系统的适应性和灵活性。

然而,C++ 组合模式也存在一些缺点:

(1)设计抽象性: 组合模式可能使设计变得过于抽象和复杂。如果对象的业务规则很复杂,实现组合模式可能会具有很大的挑战性。此外,并非所有的方法都与叶子对象子类都相关联,这可能导致一些不必要的复杂性。

(2)通用性问题: 在某些情况下,只有叶子组件需要定义某些操作,但由于组合模式的通用性,可能不得不在所有组件中定义这些操作,这可能会增加代码的复杂性。

(3)对象创建与转换问题: 当组合深度很大时,创建对象可能会变得非常麻烦,并且会创建大量的子对象。此外,在进行类型转换时,需要避免截断使用范围,否则可能会导致错误。

相关文章:

突破编程_C++_设计模式(组合模式)

1 组合模式的基本概念 C中的组合模式是一种对象结构型模式&#xff0c;它将多个对象组合成树形结构&#xff0c;以表示具有整体-部分关系的层次结构。在这个模式中&#xff0c;对单个对象&#xff08;叶子对象&#xff09;与组合对象&#xff08;容器对象&#xff09;的使用具…...

010Editor汉化版+下载+注册码+模板bug

项目场景&#xff1a; 这天我想使用我的不知名的一个破解版本的010Edit来查看一个EXE程序&#xff0c;并想使用模板功能&#xff0c;但是发现没有该模板还无法下载最新模板 问题描述 010Edit联网后需要注册码&#xff1a; 010 Editor 激活码生成器 使用方法 参照教程使用0…...

js【详解】BOM

浏览器对象模型 &#xff08;Browser obiect Mode 简称 BOM&#xff09; 浏览器对象即 window&#xff0c;调用window对象的属性和方法时&#xff0c;可以省略window window 常用的属性 Navigator 常用于获取浏览器的信息 navigator.userAgent;火狐浏览器范例&#xff1a; “…...

Leetcode 3077. Maximum Strength of K Disjoint Subarrays

Leetcode 3077. Maximum Strength of K Disjoint Subarrays 1. 解题思路 1. 朴素思路2. 算法优化 2. 代码实现 题目链接&#xff1a;3077. Maximum Strength of K Disjoint Subarrays 1. 解题思路 这道题很惭愧没有搞定&#xff0c;思路上出现了差错&#xff0c;导致一直没能…...

【JetsonNano】onnxruntime-gpu 环境编译和安装,支持 Python 和 C++ 开发

1. 设备 2. 环境 sudo apt-get install protobuf-compiler libprotoc-devexport PATH/usr/local/cuda/bin:${PATH} export CUDA_PATH/usr/local/cuda export cuDNN_PATH/usr/lib/aarch64-linux-gnu export CMAKE_ARGS"-DONNX_CUSTOM_PROTOC_EXECUTABLE/usr/bin/protoc&qu…...

知名比特币质押协议项目Babylon确认参加Hack.Summit()2024区块链开发者大会

Babylon项目已确认将派遣其项目代表出席2024年在香港数码港举办的Hack.Summit()2024区块链开发者大会。作为比特币生态的领军项目&#xff0c;Babylon积极参与全球区块链领域的交流与合作&#xff0c;此次出席大会将为其提供一个展示项目进展、交流技术与创新思路的重要平台。B…...

如何学习、上手点云算法(三):用VsCode、Visual Studio来debug基于PCL、Open3D的代码

写在前面 本文内容 以PCL 1.14.0&#xff0c;Open3D0.14.1为例&#xff0c;对基于PCL、Open3D开发的代码进行源码debug&#xff1b; 如何学习、上手点云算法系列&#xff1a; 如何学习、上手点云算法(一)&#xff1a;点云基础 如何学习、上手点云算法(二)&#xff1a;点云处理相…...

【干货】alzet渗透泵操作说明

alzet渗透泵是一款小型、可植入式的胶囊渗透泵产品&#xff0c;此产品由于其独特的渗透原理&#xff0c;深受广大科研人员的喜爱。该泵可适用于小鼠、大鼠及其他实验动物的研究&#xff0c;并且alzet渗透泵可减轻科研人员夜间及周末给药的困扰。alzet渗透泵无需外部连接或频繁处…...

CVPR 2022 Oral | Bailando: 基于编舞记忆和Actor-Critic GPT的3D舞蹈生成

目录 测试结果&#xff1a; 02 提出的方法 测试结果&#xff1a; 预测有3个步骤&#xff0c;速度比较慢 02 提出的方法 1. 针对舞蹈序列的VQ-VAE和编舞记忆 与之前的方法不同&#xff0c;我们不学习从音频特征到 3D 关键点序列的连续域的直接映射。相反&#xff0c;我们先让…...

解读电影级视频生成模型 MovieFactory

Diffusion Models视频生成-博客汇总 前言:MovieFactory是第一个全自动电影生成模型,可以根据用户输入的文本信息自动扩写剧本,并生成电影级视频。其中针对预训练的图像生成模型与视频模型之间的gap提出了微调方法非常值得借鉴。这篇博客详细解读一下这篇论文《MovieFactory:…...

【Python从入门到进阶】50、当当网Scrapy项目实战(三)

接上篇《49、当当网Scrapy项目实战&#xff08;二&#xff09;》 上一篇我们讲解了的Spider与item之间的关系&#xff0c;以及如何使用item&#xff0c;以及使用pipelines管道进行数据下载的操作&#xff0c;本篇我们来讲解Scrapy的多页面下载如何实现。 一、多页面下载原理分…...

【调试记录】vscode远程连接问题汇总

1. kex_exchange_identification kex_exchange_identification: read: Connection reset by xxx.xx.xx.x 一直连不上实验室的服务器&#xff0c;用PUTTY和Mobaxterm也不行&#xff08;报错&#xff1a;Remote side unexpectedly closed network connection&#xff09;。已知…...

基于springboot的疾病防控综合系统

采用技术 基于springboot的疾病防控综合系统的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统效果展示 用户功能效果 打卡管理 接种记录查看 公告信息查看 社区…...

js实现文本内容过长中间显示...两端正常展示

实现效果 实现思路 获取标题盒子的真实宽度, 我这里用的是clientWidth&#xff1b;获取文本内容所占的实际宽度&#xff1b;根据文字的大小计算出每个文字所占的宽度&#xff1b;判断文本内容的实际宽度是否超出了标题盒子的宽度&#xff1b;通过文字所占的宽度累加之和与标题…...

Buran勒索病毒通过Microsoft Excel Web查询文件进行传播

Buran勒索病毒首次出现在2019年5月&#xff0c;是一款新型的基于RaaS模式进行传播的新型勒索病毒&#xff0c;在一个著名的俄罗斯论坛中进行销售&#xff0c;与其他基于RaaS勒索病毒(如GandCrab)获得30%-40%的收入不同&#xff0c;Buran勒索病毒的作者仅占感染产生的25%的收入,…...

中间件 | Redis - [基本信息]

INDEX 1 常规用法2 QPS3 pipeline 1 常规用法 分布式锁 最常见用法&#xff0c;需要注意分布式锁的redis需要单点 分布式事务 分布式事务中&#xff0c;核心的技术难点其实是分布式事务这个事本身作为数据的持久化 2PC&#xff0c;比如 seata 的 AT 模式下&#xff0c;将 un…...

【Docker】Neo4j 容器化部署

Neo4j环境标准软件基于Bitnami neo4j 构建。当前版本为5.17.0 你可以通过轻云UC部署工具直接安装部署&#xff0c;也可以手动按如下文档操作&#xff0c;该项目已经全面开源&#xff0c;可以从如下环境获取 配置文件地址: https://gitee.com/qingplus/qingcloud-platform Qin…...

Visual studio编译器报1个无法解析的外部命令

解决思路&#xff1a;&#xff08;以下思路需对照代码进行逐点分析&#xff09; ①&#xff1a;代码里函数有声明&#xff0c;但是没有定义 &#xff08;初学者错这个比较多&#xff09; ②&#xff1a;类中有静态变量成员&#xff0c;没有对它进行初始化&#xff08;是变量&…...

微信小程序(五十三)修改用户头像与昵称

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.外界面个人资料基本模块 2.资料修改界面同步问题实现&#xff08;细节挺多&#xff0c;考虑了后期转服务器端的方便之处&#xff09; 源码&#xff1a; app.json {"window": {},"usingCompone…...

VUE3 显示Echarts百度地图

本次实现最终效果 技术基础以及环境要求 vue3 echarts 百度地图API 要求1&#xff1a; VUE3 环境搭建&#xff1a;https://blog.csdn.net/LQ_001/article/details/136293795 要求2&#xff1a; VUE3 echatrs 环境搭建:https://blog.csdn.net/LQ_001/article/details/1363…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

R语言速释制剂QBD解决方案之三

本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...

基于Springboot+Vue的办公管理系统

角色&#xff1a; 管理员、员工 技术&#xff1a; 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能&#xff1a; 该办公管理系统是一个综合性的企业内部管理平台&#xff0c;旨在提升企业运营效率和员工管理水…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...