设计模式(15)组合模式

一、介绍:

1、定义:组合多个对象形成树形结构以表示“整体-部分”的关系的层次结构。组合模式对叶子节点和容器节点的处理具有一致性,又称为整体-部分模式。

2、优缺点:

优点:

(1)高层模块调用简单:组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码。

(2)节点自由增加:更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码。

缺点:

(1)在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。

(2)设计较复杂,客户端需要花更多时间理清类之间的层次关系。

(3)不容易限制容器中的构件。

3、组成:

(1)抽象构件(Component)角色:它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。(总的抽象类或接口,定义一些通用的方法,比如新增、删除)。

(2)树枝构件(Composite)角色 / 中间构件:是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。

(3)树叶构件(Leaf)角色:是组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件。

// 定义抽象构件
public abstract class Component {
    protected String name;
 
    public Component(String name) {
        this.name = name;
    }
 
    public abstract void add(Component component);
 
    public abstract void remove(Component component);
 
    public abstract void display();
}
 
// 定义叶子构件
public class Leaf extends Component {
    public Leaf(String name) {
        super(name);
    }
 
    @Override
    public void add(Component component) {
        System.out.println("Cannot add to a leaf");
    }
 
    @Override
    public void remove(Component component) {
        System.out.println("Cannot remove from a leaf");
    }
 
    @Override
    public void display() {
        System.out.println("Leaf: " + name);
    }
}
 
// 定义容器构件
public class Composite extends Component {
    private List<Component> children = new ArrayList<>();
 
    public Composite(String name) {
        super(name);
    }
 
    @Override
    public void add(Component component) {
        children.add(component);
    }
 
    @Override
    public void remove(Component component) {
        children.remove(component);
    }
 
    @Override
    public void display() {
        System.out.println("Composite: " + name);
        for (Component component : children) {
            component.display();
        }
    }
}
 
// 客户端代码
public class Client {
    public static void main(String[] args) {
        Component root = new Composite("root");
        Component leaf1 = new Leaf("leaf1");
        Component leaf2 = new Leaf("leaf2");
        Component composite1 = new Composite("composite1");
        Component leaf3 = new Leaf("leaf3");
        Component composite2 = new Composite("composite2");
 
        root.add(leaf1);
        root.add(leaf2);
        root.add(composite1);
        composite1.add(leaf3);
        composite1.add(composite2);
 
        root.display();
    }
}

4、应用场景:部分、整体场景,如树形菜单,文件、文件夹的管理。

二、demo:

1、菜单:

(1)数据库model

public class MenuDTO {
    private String menuName;
    private String menuCode;
    private String parentMenuCode;
    public MenuDTO(String menuName,String menuCode,String parentMenuCode){
        this.menuCode = menuCode;
        this.menuName = menuName;
        this.parentMenuCode = parentMenuCode;
    }

   /**省略所有set、get芳芳*/
}

 抽象构件Component

public abstract class MenuComponent extends MenuDTO {

    MenuComponent(String menuName, String menuCode,String parentMenuCode) {
        super(menuName, menuCode,parentMenuCode);
    }

    void addMenu(MenuComponent component){}

    void removeMenu(MenuComponent component){}
}

(2)树枝构件(Composite): 

public class MenuVO extends MenuComponent {

    private List<MenuComponent> children = new ArrayList<>();

    MenuVO(String menuName, String menuCode,String parentMenuCode) {
        super(menuName, menuCode,parentMenuCode);
    }

    @Override
    void addMenu(MenuComponent component) {
        children.add(component);
    }

    @Override
    void removeMenu(MenuComponent component) {
    }
}

(3)树叶

public class MenuLeaf extends MenuComponent {
    MenuLeaf(String menuName, String menuCode,String parentMenuCode) {
        super(menuName, menuCode,parentMenuCode);
    }

    @Override
    void addMenu(MenuComponent component) {
        super.addMenu(component);
    }

    @Override
    void removeMenu(MenuComponent component) {
        super.removeMenu(component);
    }
}

 客户端:

public class Test {
    public static void main(String args[]) {
        MenuComponent menuVOS = listMenus();
        System.out.println(menuVOS);
    }

    public static MenuComponent listMenus(){
        //模拟数据库查询,查询所有一级菜单(menu_type = 1)、二级菜单(menu_type = 2)
        List<MenuDTO> firstMenus = new ArrayList<>();
        MenuDTO menuDTO = new MenuDTO("菜单1","cd1","root");
        firstMenus.add(menuDTO);
        menuDTO = new MenuDTO("菜单2","cd2","root");
        firstMenus.add(menuDTO);
        menuDTO = new MenuDTO("菜单3","cd3","root");
        firstMenus.add(menuDTO);

        List<MenuDTO> secondMenus = new ArrayList<>();
        menuDTO = new MenuDTO("菜单1-1","cd1-1","cd1");
        secondMenus.add(menuDTO);
        menuDTO = new MenuDTO("菜单1-2","cd1-2","cd1");
        secondMenus.add(menuDTO);
        menuDTO = new MenuDTO("菜单2-1","cd2-1","cd2");
        secondMenus.add(menuDTO);
        Map<String, List<MenuDTO>> childMenuMap = secondMenus.stream().collect(Collectors.groupingBy(MenuDTO::getParentMenuCode));
        /**实现
         * 根节点
         * 菜单1  菜单2 菜单3
         *菜单1-1 菜单1-2 菜单2-1
         * */
        //1、定义根节点
        MenuComponent root = new MenuVO("根节点","root",null);
        //2、处理菜单层级
        for(MenuDTO  firstMenu : firstMenus){
            //二级菜单
            MenuComponent firstMenuVO = new MenuVO(firstMenu.getMenuName(),firstMenu.getMenuCode(),firstMenu.getParentMenuCode());
            //三级菜单
            List<MenuDTO> secondMenuVOs = childMenuMap.get(firstMenu.getMenuCode());
            if(!CollectionUtils.isEmpty(secondMenuVOs)){
                for(MenuDTO secondMenu : secondMenuVOs){
                    MenuComponent secondMenuVO = new MenuVO(secondMenu.getMenuName(),secondMenu.getMenuCode(),secondMenu.getParentMenuCode());
                    firstMenuVO.addMenu(secondMenuVO);
                }
            }
            root.addMenu(firstMenuVO);
        }
        return root;
    }
}

运行main方法 

2、文件夹:

(1)抽象构件Component

public abstract class FileComponent {
    //文件名称
    protected String name;
    //文件的层级 1 一级目录 2 二级目录 ...
    protected Integer level;
    //文件的类型 1 文件夹 2文件
    protected Integer type;
    //添加子文件/文件夹
    public abstract void add(FileComponent fileComponent);
    //移除子文件/文件夹
    public abstract void remove(FileComponent fileComponent);
    //获取指定的子文件/文件夹
    public abstract FileComponent getChild(int index);
    //打印子 子文件/子文件夹 名称的方法
    public abstract void print();
}

(2)树枝构件(Composite)

public class FileFolder extends FileComponent{
    //文件夹可以有多个子文件夹或者子文件
    private  List<FileComponent> fileComponentList;
    
    public FileFolder(String name, Integer level, Integer type) {
        this.name = name;
        this.level = level;
        this.type = type;
        this.fileComponentList = new ArrayList<>();
    }
    @Override
    public void add(FileComponent fileComponent) {
        fileComponentList.add(fileComponent);
    }
    @Override
    public void remove(FileComponent fileComponent) {
        fileComponentList.remove(fileComponent);
    }
    @Override
    public FileComponent getChild(int index) {
        return fileComponentList.get(index);
    }
    @Override
    public void print() {
        //打印菜单名称
        for (int i = 0; i < level; i++) {
            System.out.print("\t");
        }
        System.out.println(name);
        //打印子菜单或者子菜单项名称
        for (FileComponent component : fileComponentList) {
            component.print();
        }
    }
}

(3)树叶构件(Leaf)

public class FileItem extends FileComponent{
    public FileItem(String name, Integer level, Integer type) {
        this.name = name;
        this.level = level;
        this.type = type;
    }
    @Override
    public void add(FileComponent fileComponent) {

    }
    @Override
    public void remove(FileComponent fileComponent) {

    }
    @Override
    public FileComponent getChild(int index) {
        return null;
    }
    @Override
    public void print() {
        //打印文件的名称
        for (int i = 0; i < level; i++) {
            System.out.print("\t");
        }
        System.out.println(name);
    }
}

客户端:

public class Test {
    public static void main(String[] args) {
        //定义根目录
        FileComponent rootComponent = new FileFolder("我是根目录",1,1);
        //定义二级文件夹
        FileComponent secondLevelComponent = new FileFolder("我是二级目录",2,1);
        //定义文件
        FileComponent file = new FileItem("我是文件",3,2);
        //向根目录添加二级目录
        rootComponent.add(secondLevelComponent);
        //向二级目录添加文件
        secondLevelComponent.add(file);
        //打印
        rootComponent.print();
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

stable diffusion简介和原理

Stable Diffusion中文的意思是稳定扩散&#xff0c;本质上是基于AI的图像扩散生成模型。 Stable Diffusion是一个引人注目的深度学习模型&#xff0c;它使用潜在扩散过程来生成图像&#xff0c;允许模型在生成图像时考虑到文本的描述。这个模型的出现引起了广泛的关注和讨论&am…

JAVA实现智能停车场管理系统 开源

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容A. 车主端功能B. 停车工作人员功能C. 系统管理员功能1. 停车位模块2. 车辆模块3. 停车记录模块4. IC卡模块5. IC卡挂失模块 三、界面展示3.1 登录注册3.2 车辆模块3.3 停车位模块3.4 停车数据模块3.5 IC卡档案模块3.6 IC卡挂…

香港服务器如何做负载均衡?

​  在现代互联网时代&#xff0c;随着网站访问量的不断增加&#xff0c;服务器的负载也越来越重。为了提高网站的性能和可用性&#xff0c;负载均衡成为了一种常见的解决方案。 什么是负载均衡? 负载均衡是一种技术解决方案&#xff0c;用于在多个服务器之间分配负载&#…

数据结构绪论,基本概念

目录 1.什么是数据结构&#xff1f; 2.三种数据结构&#xff1a; 3.第一章绪论 了解概念 1.几个概念 2.数据存储方式&#xff1a; 3.算法的五个重要特性: 4.算法设计的要求: 1.什么是数据结构&#xff1f; 数据 数据&#xff0c;是对客观事物的符号表示&#xff0c;在计…

Go 开发IDE全览:GoLand VS VSCode全面解析

一、引言 在软件开发的世界里&#xff0c;开发环境的选择与配置是成功项目的基础之一。特别是在Go&#xff08;又名Golang&#xff09;这样一个逐渐获得主流认同、在微服务和云计算领域有着广泛应用的编程语言中&#xff0c;选择合适的开发工具就显得尤为重要。虽然Go语言自身…

Hbase基本使用,读写原理,性能优化学习

文章目录 HBase简介HBase定义HBase数据模型**HBase** **逻辑结构****HBase** **物理存储结构****HBase** **基本架构** HBase 入门**HBase** **安装部署****HBase** 配置文件**HBase** 启动停止**HBase** **访问页面****HBase** **高可用****HBase Shell****HBase API**HBaseCo…

面向对象(类/继承/封装/多态)详解

简介: 面向对象编程&#xff08;Object-Oriented Programming&#xff0c;OOP&#xff09;是一种广泛应用于软件开发的编程范式。它基于一系列核心概念&#xff0c;包括类、继承、封装和多态。在这篇详细的解释中&#xff0c;我们将探讨这些概念&#xff0c;并说明它们如何在P…

JavaScript基础知识18——逻辑运算符之短路运算

哈喽&#xff0c;大家好&#xff0c;我是雷工。 本节学习JavaScript基础知识——逻辑运算符中的短路运算&#xff0c;以下为学习笔记。 规则&#xff1a; 1、如果是&&运算&#xff0c;只要遇到false&#xff0c;就立即短路&#xff0c;不会再执行了&#xff0c;直接返回…

应用案例|基于高精度三维机器视觉引导机器人自动分拣包裹的应用

Part.1 行业背景 近年来&#xff0c;电商高速发展&#xff0c;百万件日订单处理的超大型分拣中心模式日益普及&#xff0c;传统的人工供包模式效率低&#xff0c;难以满足高超大分拣中心对分拣包裹的需求。随着科技的进步&#xff0c;自动供包系统进入大众视野&#xff0c;成为…

基于机器视觉的火车票识别系统 计算机竞赛

文章目录 0 前言1 课题意义课题难点&#xff1a; 2 实现方法2.1 图像预处理2.2 字符分割2.3 字符识别部分实现代码 3 实现效果最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于机器视觉的火车票识别系统 该项目较为新颖&#xff0c;适合作为竞赛…

反恐精英CS1.6forMac/win中文版:动作射击游戏的巅峰之作

的游戏爱好者们&#xff0c;今天我们要向大家推荐一款让人热血沸腾的第一人称动作射击游戏——反恐精英CS1.6&#xff01;这款游戏承载了无数玩家的童年记忆&#xff0c;更是射击游戏领域中的佼佼者。 一、还原度极高的场景与道具 反恐精英CS1.6在场景和道具的还原度上做到了极…

在Mac上安装MongoDB 5.0

MongoDB 5.0安装 1、环境描述 操作系统&#xff1a;macOS 14.0 (23A344) 2、安装MongoDB 2.1、tar解压包安装 下载地址&#xff1a;Download MongoDB Community Server | MongoDB 创建一个目录&#xff0c;以便数据库将文件放入其中。&#xff08;默认情况下&#xff0c;数据…

【axios】axios的基本使用

一、 Axios简介 1、 Axios是什么&#xff1f; Axios是一个基于promise的HTTP库&#xff0c;类似于jQuery的ajax&#xff0c;用于http请求。可以应用于浏览器端和node.js&#xff0c;既可以用于客户端&#xff0c;也可以用于node.js编写的服务端。 2.、Axios特性 支持Promis…

王道p149 7.二叉树按二叉链表形式存储,写一个判别给定二叉树是否是完全二叉树的算法(c语言代码实现)

采用层次遍历算法&#xff0c;将所有结点加入队列(包括空结点)。 如果没有左孩子&#xff0c;就看有没有右孩子&#xff0c;如果有右孩子&#xff0c;那么不为完全二叉树。 如果有左孩子&#xff0c;且之前不存在缺孩子的结点&#xff0c;左孩子进队&#xff0c;如果有右孩子…

零售数据分析模板分享(通用型)

零售数据来源多&#xff0c;数据量大&#xff0c;导致数据的清洗整理工作量大&#xff0c;由于零售的特殊性&#xff0c;其指标计算组合更是多变&#xff0c;进一步导致了零售数据分析工作量激增&#xff0c;往往很难及时分析数据&#xff0c;发现问题。那怎么办&#xff1f;可…

FL Studio21.2中文版多少钱?值得下载吗

水果&#xff0c;全称Fruity Loop Studio&#xff0c;简称FL Studio。是一款全能的音乐制作软件&#xff0c;经过二十多年的演化更迭&#xff0c;其各项功能非常的先进。其开创性的Pat\song模式&#xff0c;也为初学者的学习提供了便利。那么水果音乐制作软件需要多少钱呢&…

JAVA实现校园二手交易系统 开源

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 二手商品档案管理模块2.3 商品预约管理模块2.4 商品预定管理模块2.5 商品留言板管理模块2.6 商品资讯管理模块 三、实体类设计3.1 用户表3.2 二手商品表3.3 商品预约表3.4 商品预定表3.5 留言表3.6 资讯…

【0基础学Java第一课】-- 初始Java

目录 1. 初识java1.1 Java是什么1.2 Java应用领域1.3 Java语言发展简史1.4 Java语言特性1.5 JRE与JDK1.6 Java开发环境1.6.1 安装JDK1.6.2 配置环境变量 1.7 初始Java中main函数1.7.1 JDK、JRE、JVM之间的关系 1.8 注释1.9 标识符1.10 关键字 1. 初识java 1.1 Java是什么 Jav…

计算机操作系统重点概念整理-第二章 进程管理【期末复习|考研复习】

第二章 进程管理 【期末复习|考研复习】 计算机操作系统系列文章传送门&#xff1a; 第一章 计算机系统概述 第二章 进程管理 第三章 进程同步 第四章 内存管理 第五章 文件管理 第六章 输出输出I/O管理 文章目录 第二章 进程管理 【期末复习|考研复习】前言二、进程管理2.1进…

Leetcode—66.加一【简单】

2023每日刷题&#xff08;十一&#xff09; Leetcode—66.加一 实现代码1 /*** Note: The returned array must be malloced, assume caller calls free().*/ int* plusOne(int* digits, int digitsSize, int* returnSize){int num 0;int i 0;int arr[110] {0};// 进位标识…