23种设计模式之组合设计模式

news2024/12/26 22:38:54

文章目录

  • 1. 简介
  • 2. 代码
    • 2.1 Employee (三合一)
    • 2.2 Test
    • 2.3 其他例子
  • 3. 使用场景
  • 4. 优缺点
  • 5. 总结

1. 简介

组合设计模式Composite Pattern)是一种结构型设计模式。它允许你将对象组合成树形结构来表示 “部分 - 整体” 的层次关系。组合模式使得用户对单个对象和组合对象的使用具有一致性,即可以像操作单个对象一样操作组合对象。

  • 结构组成
    • 组件(Component)接口或抽象类 :这是组合模式中的最顶层抽象,它定义了叶子节点和组合节点(包含其他子节点的节点)的公共操作接口。例如,在一个文件系统的模拟中,这个接口可能包含诸如getName()(获取名称)、getSize()(获取大小)等方法。
    • 叶子节点(Leaf):叶子节点是树形结构中的最底层对象,它没有子节点。它们实现了组件接口,但因为没有子节点,所以对于组合相关的操作(如添加或删除子节点)没有实际意义。例如,在文件系统中,文件就是叶子节点,它有自己的名称和大小,但不能包含其他文件或文件夹。
    • 组合节点(Composite):组合节点是包含子节点的节点,它也实现了组件接口。它内部维护了一个子节点的集合,并且实现了添加、删除和获取子节点等操作。在文件系统示例中,文件夹就是组合节点,它可以包含文件和其他文件夹。

2. 代码

2.1 Employee (三合一)

import java.util.ArrayList;
import java.util.List;

public class Employee {
    private String name;
    private String position;
    private int salary;

    private List<Employee> employees;

    public Employee(String name, String position, int salary) {
        this.name = name;
        this.position = position;
        this.salary = salary;
        employees = new ArrayList<>();
    }

    public void addEmployee(Employee employee) {
        employees.add(employee);
    }

    public void removeEmployee(Employee employee) {
        employees.remove(employee);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    public List<Employee> getEmployees() {
        return employees;
    }

    public void setEmployees(List<Employee> employees) {
        this.employees = employees;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", position='" + position + '\'' +
                ", salary=" + salary +
                '}';
    }
}

2.2 Test

public class Test {
    public static void main(String[] args) {
        // CEO
        Employee ceo = new Employee("dev1", "ceo", 10000);
        // 部门经理
        Employee manager = new Employee("dev2", "manager", 5000);
        // 创建销售员
        Employee saller1 = new Employee("dev3", "saller1", 4000);
        Employee saller2 = new Employee("dev3", "saller2", 4000);
        // 仓库管理员
        Employee warehouse = new Employee("dev4", "warehouse", 3000);

        ceo.addEmployee(manager);
        manager.addEmployee(saller1);
        manager.addEmployee(saller2);
        manager.addEmployee(warehouse);

        System.out.println(ceo);
        for(Employee employee : ceo.getEmployees()){
            System.out.println(employee);
            for(Employee e : employee.getEmployees()){
                System.out.println(e);
            }
        }
    }
}

输出结果:

Employee{name='dev1', position='ceo', salary=10000}
Employee{name='dev2', position='manager', salary=5000}
Employee{name='dev3', position='saller1', salary=4000}
Employee{name='dev3', position='saller2', salary=4000}
Employee{name='dev4', position='warehouse', salary=3000}

2.3 其他例子

// 组件接口
interface FileSystemComponent {
    String getName();
    long getSize();
}
// 叶子节点 - 文件
class File implements FileSystemComponent {
    private String name;
    private long size;
    public File(String name, long size) {
        this.name = name;
        this.size = size;
    }
    @Override
    public String getName() {
        return name;
    }
    @Override
    public long getSize() {
        return size;
    }
}
// 组合节点 - 文件夹
class Directory implements FileSystemComponent {
    private String name;
    private java.util.ArrayList<FileSystemComponent> children = new java.util.ArrayList<>();
    public Directory(String name) {
        this.name = name;
    }
    @Override
    public String getName() {
        return name;
    }
    @Override
    public long getSize() {
        long size = 0;
        for (FileSystemComponent child : children) {
            size += child.getSize();
        }
        return size;
    }
    public void add(FileSystemComponent component) {
        children.add(component);
    }
    public void remove(FileSystemComponent component) {
        children.remove(component);
    }
    public FileSystemComponent[] getChildren() {
        return children.toArray(new FileSystemComponent[0]);
    }
}

3. 使用场景

  • 树形结构数据表示:组合模式非常适合用于表示具有层次结构的数据,如文件系统、组织结构图、菜单系统等。例如,在一个公司的组织结构中,部门可以包含子部门和员工,使用组合模式可以方便地对整个组织结构进行操作,如计算部门的总人数、获取部门的所有下属等。
  • 统一处理对象和对象集合:当需要以相同的方式处理单个对象和对象集合时,组合模式是很好的选择。比如在图形绘制系统中,图形可以是单个的点、线,也可以是由多个图形组成的复杂图形。通过组合模式,可以统一地对这些图形进行绘制、移动、缩放等操作。

4. 优缺点

  • 优点
    • 层次结构清晰:组合模式能够清晰地表示出对象之间的层次关系,使得代码结构更加直观,易于理解和维护。
    • 客户端调用简单:客户端可以统一地使用组件接口来操作单个对象和组合对象,不需要分别处理不同类型的对象,降低了客户端代码的复杂性。
    • 可扩展性强:可以方便地添加新的叶子节点或组合节点类型,只要它们实现了组件接口,就可以融入到现有的层次结构中。
  • 缺点
    • 设计复杂度过高:对于简单的层次结构,使用组合模式可能会使设计变得过于复杂,增加了代码的理解和实现成本。
    • 限制了叶子节点和组合节点的差异性:由于叶子节点和组合节点都要实现组件接口,可能会导致一些不符合实际情况的接口实现。例如,叶子节点可能不需要实现与子节点相关的操作,但为了符合接口要求,也需要提供这些操作的空实现。

5. 总结

无,哈哈

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

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

相关文章

关于单片机的原理与应用!

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///计算机爱好者&#x1f60a;///目前正在学习C&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于单片…

深入解析 MySQL 启动方式:`systemctl` 与 `mysqld` 的对比与应用

目录 前言1. 使用 systemctl 启动 MySQL1.1 什么是 systemctl1.2 systemctl 启动 MySQL 的方法1.3 应用场景1.4 优缺点优点缺点 2. 使用 mysqld 命令直接启动 MySQL2.1 什么是 mysqld2.2 mysqld 启动 MySQL 的方法2.3 应用场景2.4 优缺点优点缺点 3. 对比分析结语 前言 MySQL …

简单介绍下 VitePress 中的 vp-doc 和 vp-raw

VitePress 是一个轻量级的静态网站生成器&#xff0c;专为快速构建文档网站而设计。它是基于 Vite 和 Vue 3 构建的&#xff0c;旨在提供快速的开发体验和高效的构建过程。 存在两个需要注意的点&#xff1a;vp-doc 和 vp-raw&#xff0c;它们代表了不同的 CSS 样式类和用途&a…

HTML前端开发-- Flex布局详解及实战

引言 Flex布局&#xff0c;全称为Flexible Box Layout&#xff0c;是一种现代CSS布局技术&#xff0c;它提供了一种更有效的方式来设计响应式布局和复杂页面布局。本文将详细介绍Flex布局的基本概念、属性以及实战应用。 一、基本概念 Flex布局的核心是Flex容器&#xff08;…

【前端】理解 JavaScript 中 typeof 操作符的独特行为

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 &#x1f4af;前言&#x1f4af;typeof 操作符的基本使用&#x1f4af;为什么 typeof 数组是 "object"&#xff1f;&#x1f4af;为什么 typeof {} 返回 "object"&#xff1f;&…

一键解析RAW文件,GPS定位展示,摄影师专用照片管理软件

作为一款精心打造的数码影像管理工具&#xff0c;bkViewer以其轻量化设计和强大的功能特性脱颖而出。这款软件不仅能够完美处理各类主流图片格式&#xff0c;更整合了专业级的图像信息处理系统&#xff0c;包含完整的EXIF、XMP、IPTC、GPS、ICC等元数据解析能力&#xff0c;并通…

import.meta.glob动态加载图片

import.meta.glob 基于Vite&#xff08;Vue 3 默认构建工具&#xff09;&#xff0c;用于动态导入模块&#xff0c;特别是当你需要批量导入文件或模块时. const modules import.meta.glob(/path/to/files/**/*.js);注意&#xff1a;import.meta.glob 是针对 源代码&#xff…

[高阶数据结构六]最短路径算法

1.前言 最短路径算法是在图论的基础上讲解的&#xff0c;如果你还不知道图论的相关知识的话&#xff0c;可以阅读下面几篇文章。 [高阶数据结构四] 初始图论_初始图结构-CSDN博客 [高阶数据结构五] 图的遍历和最小生成树_图的遍历和生成树求解-CSDN博客 本章重点&#xff1a;…

开源的跨平台SQL 编辑器Beekeeper Studio

一款开源的跨平台 SQL 编辑器&#xff0c;提供 SQL 语法高亮、自动补全、数据表内容筛选与过滤、连接 Web 数据库、存储历史查询记录等功能。该编辑器支持 SQLite、MySQL、MariaDB、Postgres 等主流数据库&#xff0c;并兼容 Windows、macOS、Linux 等桌面操作系统。 项目地址…

mysql 5.7安装及安装后无法启动问题处理

下载安装包&#xff0c;直接解压 配置环境变量 创建my.ini文件 [mysqld] #端口号 port 3306 #mysql-5.7.27-winx64的路径 basedirD:/soft/mysql57 #mysql-5.7.27-winx64的路径\data datadirD:/soft/mysql57/data #最大连接数 max_connections200 #编码 character-set-server…

spine 动画层 动态权重

前奏.业务背景 这边想实现一个功能&#xff0c;项目中有 一只猫 猫的头会盯着逗猫棒移动。因为素材还没到所以这里使用了 spine 自带的猫头鹰。他的动画 刚好挺有针对性&#xff1a;&#xff08;关联上篇&#xff09;https://blog.csdn.net/nicepainkiller/article/details/144…

Spark 内存管理机制

Spark 内存管理 堆内内存和堆外内存 作为一个 JVM 进程&#xff0c;Executor 的内存管理建立在 JVM(最小为六十四分之一&#xff0c;最大为四分之一)的内存管理之上&#xff0c;此外spark还引入了堆外内存&#xff08;不在JVM中的内存&#xff09;&#xff0c;在spark中是指不…

Vision Transformer(vit)的主干

图解&#xff1a; 代码&#xff1a; class VisionTransformer(nn.Module):def __init__(self, img_size224, patch_size16, in_c3, num_classes1000,embed_dim768, depth12, num_heads12, mlp_ratio4.0, qkv_biasTrue,qk_scaleNone, representation_sizeNone, distilledFalse,…

mongodb配置ssl连接

mongodb5.0.9 centos7.6x86 1、正常启动mongod -f mongodb.conf 2、生成所需要的ssl证书 服务端ssl配置&#xff1a; 2.1生成ca.pem证书 #-x509&#xff1a; 用于生成自签证书&#xff0c;如果不是自签证书则不需要此项 #-days: 证书的有效期限&…

Linux 中的 ls 命令:从使用到源码解析

ls 命令是 Linux 系统中最常用和最基本的命令之一。下面将深入探讨 ls 命令的使用方法、工作原理、源码解析以及实际应用场景。 1. ls 命令的使用** ls 命令用于列出目录内容&#xff0c;显示文件和目录的详细信息。 1.1 基本用法 ls [选项] [文件或目录]例如&#xff1a; …

Python 【图像分类】之 PyTorch 进行猫狗分类功能的实现(Swanlab训练可视化/ Gradio 实现猫狗分类 Demo)

Python 【图像分类】之 PyTorch 进行猫狗分类功能的实现(Swanlab训练可视化/ Gradio 实现猫狗分类 Demo) 目录 Python 【图像分类】之 PyTorch 进行猫狗分类功能的实现(Swanlab训练可视化/ Gradio 实现猫狗分类 Demo) 一、简单介绍 二、PyTorch 三、CNN 1、神经网络 2、卷…

【C语言】结构体(二)

一&#xff0c;结构体的初始化 和其它类型变量一样&#xff0c;对结构体变量可以在定义时指定初始值 #include <stdio.h> #include <stdlib.h> struct books // 结构体类型 {char title[50];char author[50]; //结构体成员char subject[100];int book_id; }…

C++(4个类型转换)

1. C语言中的类型转换 1. 隐式 类型转换&#xff1a; 具有相近的类型才能进行互相转换&#xff0c;如&#xff1a;int,char,double都表示数值。 2. 强制类型转换&#xff1a;能隐式类型转换就能强制类型转换&#xff0c;隐式类型之间的转换类型强相关&#xff0c;强制类型转换…

Windows下从命令行(Powershell/CMD)发送内容到系统通知中心

Windows下从命令行&#xff08;Powershell/CMD&#xff09;发送内容到系统通知中心 01 前言 在平时写脚本的时候&#xff0c;将日志等信息直接输出到控制台固然是最直接的&#xff0c;而如果是一些后台执行的任务&#xff0c;不需要时刻关注运行细节但是又想知道一些大致的情…

四、初识C语言(4)

一、作业&#xff1a;static修饰局部变量 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> //作业&#xff1a;static修饰局部变量 int sum (int a) {int c 0;static int b 3;c 1;b 2;return (abc); } int main() {int i 0;int a …