零基础设计模式——结构型模式 - 组合模式
第三部分:结构型模式 - 组合模式 (Composite Pattern)
在学习了桥接模式如何分离抽象和实现以应对多维度变化后,我们来探讨组合模式。组合模式允许你将对象组合成树形结构来表现“整体-部分”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
- 核心思想:将对象组合成树状结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
组合模式 (Composite Pattern)
“将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象(叶子节点)和组合对象(容器节点)的使用具有一致性。” (Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.)
想象一下电脑文件系统的目录结构。一个目录可以包含文件(叶子节点),也可以包含其他目录(容器节点),这些子目录又可以包含文件或其他目录,形成一个树形结构。无论你操作的是一个文件还是一个目录(比如计算大小、显示名称),你可能希望用类似的方式来对待它们。
组合模式正是为了解决这类问题而设计的。
1. 目的 (Intent)
组合模式的主要目的:
- 表示部分-整体层次结构:清晰地表示对象之间的树形结构关系。
- 统一操作接口:使得客户端可以一致地处理单个对象(叶子)和对象的组合(容器/分支)。客户端不需要区分它正在处理的是一个叶子节点还是一个容器节点,从而简化了客户端代码。
- 递归组合:容器节点可以包含叶子节点,也可以包含其他容器节点,形成递归结构。
2. 生活中的例子 (Real-world Analogy)
-
公司组织架构:
- 一个公司(
Company
- 根容器)由多个部门(Department
- 容器)组成。 - 每个部门可以包含员工(
Employee
- 叶子),也可以包含子部门(SubDepartment
- 容器)。 - 无论是计算整个公司的总薪资,还是某个部门的总薪资,或者某个员工的薪资,都可以通过一个统一的操作(如
getSalary()
)来递归地完成。
- 一个公司(
-
图形用户界面 (GUI):
- 一个窗口(
Window
- 根容器)可以包含面板(Panel
- 容器)和各种控件如按钮(Button
- 叶子)、文本框(TextBox
- 叶子)。 - 面板本身也可以包含其他面板或控件。
- 当需要绘制整个窗口时,窗口会调用其子组件的绘制方法,子面板会再调用其子组件的绘制方法,直到叶子控件被绘制。这个过程对调用者(如窗口管理器)来说是统一的。
- 一个窗口(
-
菜单系统:
- 一个菜单栏(
MenuBar
- 根容器)包含多个菜单(Menu
- 容器)。 - 每个菜单可以包含菜单项(
MenuItem
- 叶子),也可以包含子菜单(SubMenu
- 容器)。 - 点击一个菜单项执行操作,点击一个子菜单则展开它。对用户来说,操作菜单和菜单项的方式是相似的。
- 一个菜单栏(
-
装配线上的部件:
- 一个复杂产品(如汽车 - 根容器)由许多主要部件(如引擎、底盘 - 容器)组成。
- 每个主要部件又由更小的零件(如螺丝、活塞 - 叶子)或子部件(如变速箱 - 容器)组成。
- 计算总成本或总重量时,可以递归地累加所有部分的成本或重量。
3. 结构 (Structure)
组合模式通常包含以下角色:
- Component (组件接口):为组合中的对象声明接口。它既可以代表叶子 (Leaf) 也可以代表容器 (Composite)。它通常声明了所有类共有的一系列操作,如
add()
,remove()
,getChild()
,operation()
等。对于叶子节点,add()
,remove()
,getChild()
等管理子节点的操作可能没有意义,可以提供默认实现(如抛出异常或空操作)。 - Leaf (叶子节点):在组合中表示叶节点对象,叶节点没有子节点。它实现了 Component 接口中定义的操作。
- Composite (容器/组合节点):定义有子部件的那些部件的行为。存储子部件并在 Component 接口中实现与子部件相关的操作(如
add()
,remove()
,getChild()
)。Composite 的operation()
方法通常会递归调用其子组件的operation()
方法。 - Client (客户端):通过 Component 接口操纵组合部件的对象。
透明方式 vs 安全方式:
- 透明方式 (Transparent):
Component
接口中声明所有管理子对象的方法(add
,remove
,getChild
)。这样客户端可以统一对待所有组件,无需区分叶子和容器。但叶子节点需要对这些管理方法提供空实现或抛出异常,因为它们没有子节点。这是上图所示的方式。 - 安全方式 (Safe):只在
Composite
类中声明管理子对象的方法。客户端在调用这些方法前需要判断对象类型是否为Composite
。这样叶子节点就不需要实现不相关的方法,更安全,但客户端处理起来稍微麻烦一些。
通常推荐透明方式,因为它简化了客户端代码,尽管可能牺牲一点类型安全(叶子节点可能会被错误地调用 add
方法)。
4. 适用场景 (When to Use)
- 当你希望表示对象的部分-整体层次结构时。
- 当你希望客户端代码可以统一处理组合结构中的单个对象和组合对象时,而无需关心其具体是叶子还是容器。
- 当对象的结构是递归的,并且你想以统一的方式处理这种结构时。
- 当你想让客户能够增加新的组件类型(叶子或容器)而无需修改现有使用该结构的代码时。
5. 优缺点 (Pros and Cons)
优点:
- 简化客户端代码:客户端可以一致地使用组合结构中的所有对象,无需编写特殊的代码来区分叶子和容器。
- 易于增加新类型的组件:可以很容易地增加新的
Leaf
或Composite
类,它们都遵循Component
接口,对现有结构和客户端代码影响小,符合开闭原则。 - 使层次结构更清晰:代码直接反映了对象的树形结构。
缺点:
- 使设计过于通用(透明方式下):如果采用透明方式,
Component
接口需要包含所有可能的操作,包括那些只对Composite
有意义的操作(如add
,remove
)。这可能使得叶子节点的接口不太纯粹,因为它们不得不实现一些无用的方法。 - 难以限制组合中的组件类型:有时你可能希望一个
Composite
只能包含特定类型的Component
。标准组合模式很难直接实现这种约束,可能需要额外的类型检查或使用泛型(如果语言支持)。 - 如果管理子节点的操作过于复杂,Component接口会变得臃肿。
6. 实现方式 (Implementations)
让我们以一个图形绘制系统为例,其中可以有简单的图形(如点、线、圆 - 叶子)和复杂的组合图形(可以包含其他简单或复杂图形 - 容器)。
组件接口 (Graphic - Component)
// graphic.go (Component)
package graphicsimport "fmt"// Graphic 组件接口
type Graphic interface {Draw() // 所有图形对象共有的操作:绘制Add(g Graphic) error // 添加子图形 (对叶子节点无意义)Remove(g Graphic) error // 移除子图形 (对叶子节点无意义)GetChild(index int) (Graphic, error) // 获取子图形 (对叶子节点无意义)GetName() string // 获取图形名称
}
// Graphic.java (Component)
package com.example.graphics;// 组件接口
public interface Graphic {void draw(); // 所有图形对象共有的操作:绘制String getName(); // 获取图形名称// 管理子图形的方法 (透明方式)// 对于叶子节点,这些方法通常会抛出UnsupportedOperationException或空实现default void add(Graphic graphic) {throw new UnsupportedOperationException("Cannot add to a leaf graphic.");}default void remove(Graphic graphic) {throw new UnsupportedOperationException("Cannot remove from a leaf graphic.");}default Graphic getChild(int index) {throw new UnsupportedOperationException("Leaf graphic has no children.");}
}
叶子节点 (Dot, Line, Circle - Leaf)
// dot.go (Leaf)
package graphicsimport "fmt"// Dot 叶子节点
type Dot struct {Name stringX, Y int
}func NewDot(name string, x, y int) *Dot {return &Dot{Name: name, X: x, Y: y}
}func (d *Dot) GetName() string {return d.Name
}func (d *Dot) Draw() {fmt.Printf("Drawing Dot '%s' at (%d, %d)\n", d.Name, d.X, d.Y)
}func (d *Dot) Add(g Graphic) error {return fmt.Errorf("cannot add to a leaf graphic (Dot: %s)", d.Name)
}func (d *Dot) Remove(g Graphic) error {return fmt.Errorf("cannot remove from a leaf graphic (Dot: %s)", d.Name)
}func (d *Dot) GetChild(index int) (Graphic, error) {return nil, fmt.Errorf("leaf graphic (Dot: %s) has no children", d.Name)
}// line.go (Leaf) - 类似 Dot,省略 Add, Remove, GetChild 的错误实现
type Line struct {Name stringStartX, StartY intEndX, EndY int
}func NewLine(name string, sx, sy, ex, ey int) *Line {return &Line{Name: name, StartX: sx, StartY: sy, EndX: ex, EndY: ey}
}func (l *Line) GetName() string {return l.Name
}func (l *Line) Draw() {fmt.Printf("Drawing Line '%s' from (%d,%d) to (%d,%d)\n", l.Name, l.StartX, l.StartY, l.EndX, l.EndY)
}func (l *Line) Add(g Graphic) error { return fmt.Errorf("cannot add to Line") }
func (l *Line) Remove(g Graphic) error { return fmt.Errorf("cannot remove from Line") }
func (l *Line) GetChild(index int) (Graphic, error) { return nil, fmt.Errorf("Line has no children") }
// Dot.java (Leaf)
package com.example.graphics;public class Dot implements Graphic {private String name;private int x, y;public Dot(String name, int x, int y) {this.name = name;this.x = x;this.y = y;}@Overridepublic String getName() {return name;}@Overridepublic void draw() {System.out.printf("Drawing Dot '%s' at (%d, %d)%n", name, x, y);}// add, remove, getChild 使用接口的默认实现 (抛出UnsupportedOperationException)
}// Line.java (Leaf)
package com.example.graphics;public class Line implements Graphic {private String name;private int startX, startY, endX, endY;public Line(String name, int startX, int startY, int endX, int endY) {this.name = name;this.startX = startX;this.startY = startY;this.endX = endX;this.endY = endY;}@Overridepublic String getName() {return name;}@Overridepublic void draw() {System.out.printf("Drawing Line '%s' from (%d,%d) to (%d,%d)%n", name, startX, startY, endX, endY);}
}
容器节点 (CompoundGraphic - Composite)
// compound_graphic.go (Composite)
package graphicsimport ("fmt"
)// CompoundGraphic 容器节点
type CompoundGraphic struct {Name stringchildren []Graphic
}func NewCompoundGraphic(name string) *CompoundGraphic {return &CompoundGraphic{Name: name,children: make([]Graphic, 0),}
}func (cg *CompoundGraphic) GetName() string {return cg.Name
}func (cg *CompoundGraphic) Draw() {fmt.Printf("Drawing CompoundGraphic '%s':\n", cg.Name)for _, child := range cg.children {fmt.Print(" ") // Indent for claritychild.Draw()}fmt.Printf("Finished Drawing CompoundGraphic '%s'\n", cg.Name)
}func (cg *CompoundGraphic) Add(g Graphic) error {cg.children = append(cg.children, g)fmt.Printf("Added %s to %s\n", g.GetName(), cg.GetName())return nil
}func (cg *CompoundGraphic) Remove(g Graphic) error {found := falsenewChildren := make([]Graphic, 0)for _, child := range cg.children {if child == g { // Pointer comparison for simplicity, or use unique IDfound = truefmt.Printf("Removed %s from %s\n", g.GetName(), cg.GetName())continue}newChildren = append(newChildren, child)}cg.children = newChildrenif !found {return fmt.Errorf("child graphic '%s' not found in '%s'", g.GetName(), cg.GetName())}return nil
}func (cg *CompoundGraphic) GetChild(index int) (Graphic, error) {if index < 0 || index >= len(cg.children) {return nil, fmt.Errorf("index out of bounds for CompoundGraphic '%s'", cg.Name)}return cg.children[index], nil
}
// CompoundGraphic.java (Composite)
package com.example.graphics;import java.util.ArrayList;
import java.util.List;public class CompoundGraphic implements Graphic {private String name;private List<Graphic> children = new ArrayList<>();public CompoundGraphic(String name) {this.name = name;}@Overridepublic String getName() {return name;}@Overridepublic void draw() {System.out.printf("Drawing CompoundGraphic '%s':%n", name);for (Graphic child : children) {System.out.print(" "); // Indent for claritychild.draw();}System.out.printf("Finished Drawing CompoundGraphic '%s'%n", name);}@Overridepublic void add(Graphic graphic) {children.add(graphic);System.out.printf("Added %s to %s%n", graphic.getName(), this.name);}@Overridepublic void remove(Graphic graphic) {if (children.remove(graphic)) {System.out.printf("Removed %s from %s%n", graphic.getName(), this.name);} else {System.out.printf("Graphic %s not found in %s for removal%n", graphic.getName(), this.name);}}@Overridepublic Graphic getChild(int index) {if (index >= 0 && index < children.size()) {return children.get(index);}throw new IndexOutOfBoundsException("Index out of bounds for CompoundGraphic '" + name + "'");}
}
客户端使用
// main.go (示例用法)
/*
package mainimport ("./graphics""fmt"
)func main() {// Create leaf objectsdot1 := graphics.NewDot("Dot1", 10, 20)line1 := graphics.NewLine("Line1", 0, 0, 100, 100)dot2 := graphics.NewDot("Dot2", 50, 60)// Create a compound graphiccompound1 := graphics.NewCompoundGraphic("Picture1")compound1.Add(dot1)compound1.Add(line1)// Create another compound graphic and add the first one to itmainPicture := graphics.NewCompoundGraphic("MainCanvas")mainPicture.Add(compound1)mainPicture.Add(dot2)fmt.Println("\n--- Drawing Main Canvas ---")mainPicture.Draw() // Client treats mainPicture (Composite) and dot1 (Leaf) uniformly via Graphic interfacefmt.Println("\n--- Trying to add to a leaf (should fail) ---")err := dot1.Add(line1)if err != nil {fmt.Println("Error as expected:", err)}fmt.Println("\n--- Removing an element ---")compound1.Remove(dot1)fmt.Println("\n--- Drawing Main Canvas After Removal ---")mainPicture.Draw()// Accessing a childchild, err := compound1.GetChild(0)if err == nil {fmt.Printf("\n--- Child 0 of Picture1 is: %s ---\n", child.GetName())child.Draw()} else {fmt.Println("Error getting child:", err)}
}
*/
// Main.java (示例用法)
/*
package com.example;import com.example.graphics.*;public class Main {public static void main(String[] args) {// Create leaf objectsGraphic dot1 = new Dot("Dot1", 10, 20);Graphic line1 = new Line("Line1", 0, 0, 100, 100);Graphic dot2 = new Dot("Dot2", 50, 60);// Create a compound graphicCompoundGraphic compound1 = new CompoundGraphic("Picture1");compound1.add(dot1);compound1.add(line1);// Create another compound graphic and add the first one to itCompoundGraphic mainPicture = new CompoundGraphic("MainCanvas");mainPicture.add(compound1);mainPicture.add(dot2);System.out.println("\n--- Drawing Main Canvas ---");mainPicture.draw(); // Client treats mainPicture (Composite) and dot1 (Leaf) uniformly via Graphic interfaceSystem.out.println("\n--- Trying to add to a leaf (should throw exception) ---");try {dot1.add(line1);} catch (UnsupportedOperationException e) {System.out.println("Exception as expected: " + e.getMessage());}System.out.println("\n--- Removing an element ---");compound1.remove(dot1);System.out.println("\n--- Drawing Main Canvas After Removal ---");mainPicture.draw();// Accessing a childtry {Graphic child = compound1.getChild(0);System.out.printf("%n--- Child 0 of Picture1 is: %s ---%n", child.getName());child.draw();} catch (IndexOutOfBoundsException e) {System.out.println("Error getting child: " + e.getMessage());}}
}
*/
7. 总结
组合模式通过引入一个共同的组件接口,使得客户端可以统一处理单个对象(叶子)和对象的组合(容器)。它非常适合用来表示具有“部分-整体”层次结构的对象,并能有效地简化客户端与这种复杂结构交互的方式。通过递归组合,可以构建出任意复杂的树形结构,同时保持操作的一致性。
记住它的核心:统一对待单个对象和组合对象,形成树形结构。
相关文章:

零基础设计模式——结构型模式 - 组合模式
第三部分:结构型模式 - 组合模式 (Composite Pattern) 在学习了桥接模式如何分离抽象和实现以应对多维度变化后,我们来探讨组合模式。组合模式允许你将对象组合成树形结构来表现“整体-部分”的层次结构。组合模式使得用户对单个对象和组合对象的使用具…...
额度年审领域知识讲解
金融领域的“额度年审”是一个非常重要的常规性工作。它指的是金融机构(主要是银行)对其授予客户的各种信用额度或授信额度,在授信有效期内(通常是一年)进行周期性的重新评估、审查和确认的过程。 核心目的࿱…...

腾讯云国际站可靠性测试
在数字化转型加速的今天,企业对于云服务的依赖已从“可选”变为“必需”。无论是跨境电商的实时交易,还是跨国企业的数据协同,云服务的可靠性直接决定了业务连续性。作为中国领先的云服务提供商,腾讯云国际站(Tencent …...

自定义异常小练习
在开始之前,让我们高喊我们的口号: 键盘敲烂,年薪百万! 目录 键盘敲烂,年薪百万! 异常综合练习: 自定义异常 异常综合练习: 自定义异常: 定义异常类写继承关系空参构造带参构造 自定…...

SpringBoot整合MinIO实现文件上传
使用Spring Boot与JSP和MinIO(一个开源对象存储系统,兼容Amazon S3)进行集成,您可以创建一个Web应用来上传、存储和管理文件。以下是如何将Spring Boot、JSP和MinIO集成的基本步骤: 这个是minio正确启动界面 这个是min…...

基于面向对象设计的C++日期推算引擎:精准高效的时间运算实现与运算重载工程化实践
前引: 在软件开发中,时间与日期的处理是基础但极具挑战性的任务。传统的手工日期运算逻辑往往面临闰年规则、月份天数动态变化、时区转换等复杂场景的容错难题,且代码冗余度高、可维护性差。本文将深入探讨如何利用C的面向对象特性与成员函数…...

如何把 Microsoft Word 中所有的汉字字体替换为宋体?
Ctrl H ,然后,点击更多,勾选使用通配符,查找内容中填入 [一-龥]{1,}, 这是 Word 通配符匹配汉字的经典写法(匹配 Unicode 范围内的 CJK 汉字)。 然后, “替换为”留空,点…...
02. [Python+Golang+PHP]三数之和,多种语言实现最优解demo
一、问题描述:三数之和 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意:答案中…...
MongoDB选择理由
1.简介 MongoDB是一个基于分布式文件存储的数据库由C语言编写,旨在为WEB应用提供可扩展的高性能数据存储解决方案。MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。Mongo最大的特点是…...

倚光科技在二元衍射面加工技术上的革新:引领光学元件制造新方向
倚光科技二元衍射面加工技术(呈现出细腻的光碟反射纹路) 在光学元件制造领域,二元衍射面的加工技术一直是行业发展的关键驱动力之一。其精准的光相位调制能力,在诸多前沿光学应用中扮演着不可或缺的角色。然而,长期以来…...

驱动开发(2)|鲁班猫rk3568简单GPIO波形操控
上篇文章写了如何下载内核源码、编译源码的详细步骤,以及一个简单的官方demo编译,今天分享一下如何根据板子的引脚写自己控制GPIO进行高低电平反转。 想要控制GPIO之前要学会看自己的引脚分布图,我用的是鲁班猫RK3568,引脚分布图如…...

《软件工程》第 3 章 -需求工程概论
在软件工程的开发流程中,需求工程是奠定项目成功基础的关键环节。它专注于获取、分析、定义和管理软件需求,确保开发出的软件能真正满足用户需求。接下来,我们将按照目录内容,结合 Java 代码和实际案例,深入讲解需求工…...

VMware-MySQL主从
MySQL主从 服务器信息 服务器类型角色主机地址主机名称虚拟机master192.168.40.128test-1虚拟机slave192.168.40.129test-2 Master 配置(192.168.40.128) 删除自动生成的配置 /var/lib/mysql/auto.cnf [roottest-1 ~]# rm -rf /var/lib/mysql/auto.…...
ArcGIS Pro 3.4 二次开发 - 几何
环境:ArcGIS Pro SDK 3.4 + .NET 8 文章目录 几何1 空间参考1.1 从已知ID构建空间参考1.2 从字符串构建空间参考1.3 使用 WGS84 空间参考1.4 使用已知ID构建带有垂直坐标系的空间参考1.5 使用垂直坐标系从字符串构建SpatialReference1.6 使用自定义投影坐标系(PCS)构建空间参…...

2023-ICLR-ReAct 首次结合Thought和Action提升大模型解决问题的能力
关于普林斯顿大学和Google Research, Brain Team合作的一篇文章, 在语言模型中协同Reasoning推理和Action行动。 论文地址:https://arxiv.org/abs/2210.03629 代码:https://github.com/ysymyth/ReAct.git 其他复现 langchain :https://pytho…...

Rust 开发的一些GUI库
最近考虑用Rust干点什么,于是搜集了下资料——根据2025年最新调研结果和社区实践,Rust GUI库生态已形成多个成熟度不同的解决方案。以下是当前主流的GUI库分类及特点分析,结合跨平台支持、开发体验和实际应用场景进行综合评估: 一…...

【第四十六周】文献阅读:从 RAG 到记忆:大型语言模型的非参数持续学习
目录 摘要Abstract从 RAG 到记忆:大型语言模型的非参数持续学习研究背景方法论1. 离线索引(Offline Indexing)2. 在线检索(Online Retrieval)具体细节 创新性实验结果局限性总结 摘要 本论文旨在解决当前检索增强生成…...

从智能提效到产品赋能的架构实践
摘要 本文深入探讨了企业级系统从智能化提效阶段向产品赋能阶段演进的架构实践路径。通过分析传统架构的局限性,提出了以用户价值为导向的现代化架构设计理念,并结合实际案例展示了如何构建可扩展、高可用、智能化的产品架构体系。 1. 引言 在数字化转型的浪潮中,企业技术…...
《Python 虚拟环境完全指南:如何管理项目依赖,避免版本冲突》
《Python 虚拟环境完全指南:如何管理项目依赖,避免版本冲突》 1. 引言 在 Python 开发中,依赖管理是至关重要的环节。不同项目可能需要不同的库版本,而全局安装库可能导致版本冲突或环境污染。为解决这一问题,Python 提供了虚拟环境(venv、virtualenv),帮助开发者隔离…...
微信小程序带数组参数跳转页面,微信小程序跳转页面带数组参数
在微信小程序中,带数组参数跳转页面需要通过JSON序列化和URL编码处理,以下是具体实现方法 传递数组参数(发送页面) wx.navigateTo({url: /pages/targetPage?arr encodeURIComponent(JSON.stringify(yourArray)) });接收数组参…...
服务器开机自启动服务
前言: 将服务器中脚本开启自启动执行 步骤: 1.创建一个 systemd 服务文件: /etc/systemd/system/ 目录下创建一个新的服务文件。例如,命名为 myapp.service: sudo nano /etc/systemd/system/myapp.service2.编写 [Unit] Descri…...

关于OT IIOT系统远程访问的零信任安全
什么是OT & IIOT?—— 工业领域的“操作基石”与“智能升级” 在工业数字化转型的浪潮中,OT(运营技术)与IIoT(工业物联网)是两个核心概念。前者是工业生产的“神经中枢”,后者是驱动智能升…...

【Doris基础】Apache Doris vs 传统数据仓库:架构与性能的全面对比
目录 1 引言 1.1 传统数据仓库的发展 1.2 现代分析型数据库的崛起 2 核心架构对比 2.1 传统数据仓库的架构 2.2 Doris的架构设计 3 关键技术差异 3.1 存储引擎对比 3.2 查询执行对比 3.3 数据摄入方式对比 4 性能与扩展性对比 4.1 性能基准对比 4.2 扩展性对比 5…...

【VScode】python初学者的有力工具
还记得23年11月,我还在欣喜Spyder像Rstudio一样方便。 但苦于打开软件打开太卡、太耗时(初始化-再加载一些东西),一度耗费了我学习的热情。 就在24年5月份,别人推荐下发现了一个更加轻量级、方便又快速的ID࿰…...
Linux系统中为Qt项目封装一个udp客户端类
Linux系统中为Qt项目封装一个udp客户端类 一、场景 在日常的Qt项目中,我们常用的就是网络通信协议是TCP/UDP, 对于网络协议,Qt都已经封装好了自己的TCP/UDP类,QTcpSocket/QUdpSocket,这些类非常的好用,也非常的易用。 这些类继承自QAbstractSocket,而QAbstractSocket类…...

443端口:HTTPS通信的安全基石
在互联网通信中,端口是数据传输的虚拟通道,每个端口对应特定的服务或协议。其中,443端口 作为 HTTPS协议 的默认端口,在现代网络安全中扮演着至关重要的角色。 一、443端口的核心作用 HTTPS加密通信 443端口是HTTPS(…...

宝塔安装WordPress程序
宝塔安装WordPress程序 一、提前准备1,下载WordPress2,在宝塔创建站点 二、部署项目1,上传下载的wordpress压缩包至创建的项目根目录下并解压 三、wordpress安装1,在浏览器打开创建的网站2,开始按照流程安装配置数据库…...

Agent 的7 中设计模式
这里写自定义目录标题 建立有效的Agent什么是Agent?何时(以及何时不使用)使用代理何时以及如何使用框架构建块、工作流和Agent构建模块:增强型LLM(The augmented LLM)工作流程:提示链接(Prompt chaining)工作流程&…...

OpenGAN:基于开放数据生成的开放集识别
简介 简介:这次学习的OpenGAN主要学习一个思路,跳出传统GAN对于判断真假的识别到判断是已知种类还是未知种类。重点内容不在于代码而是思路,会简要给出一个设计的代码。 论文题目:OpenGAN: Open-Set Recognition via Open Data …...

【node】Express创建服务器
Express是基于Node.js平台,快速、开放、极简的Web开发框架。基于http的express是专门用来创建web服务器的,可以极大的提高开发效率。 Express的创建的服务器 1 web网站服务器 专门对外提供web网页资源的服务器 2 Api接口服务器 专门对外提供Api接口的服…...