设计模式(15)组合模式

news2024/11/15 8:28:49

一、介绍:

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();
    }
}

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

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

相关文章

国外问卷调查赚钱靠谱吗?

大家好&#xff0c;我是橙河网络&#xff0c;这几年的国外问卷调查项目可真是火得一塌糊涂&#xff0c;不少人靠这个项目赚得是盆满钵满&#xff0c;让人直流口水。今天&#xff0c;我就来给大家详细扒一扒这个国外问卷调查赚钱靠谱吗&#xff1f; 首先&#xff0c;我得跟大家…

家长扫码查成绩

亲爱的老师&#xff0c;你是否曾为了如何让家长更方便地查询学生的成绩而烦恼&#xff1f;现在&#xff0c;我们为你介绍一款简单易用的成绩查询系统&#xff0c;让家长只需轻轻一扫&#xff0c;即可查看孩子的成绩。 一、什么是成绩查询系统&#xff1f; 成绩查询系统是一款专…

TTS | 一文总览语音合成系列基础知识及简要介绍

Text-to-Speech&#xff08;通常缩写为TTS&#xff09;是指一种将文本读成音频的技术。换句话说&#xff0c;它指的是一种模型&#xff0c;在该模型中&#xff0c;当文本或类似于字符的东西作为输入时&#xff0c;会生成波形音频作为输出。 但实际上&#xff0c;这个 TTS 的音…

iOS调试技巧——使用Python 自定义LLDB

一、类介绍 在使用Python 自定义LLDB之前,先了解一下LLDB的一些类型 SBTarget 正在被调试的程序SBProcess 和程序关联的具体的进程SBThread 执行的线程SBFrame 和线程关联的一个栈帧SBVariable 变量,寄存器或是一个表达式一般情况下,我们取到SBFrame就可以进行方法调用来打…

Spring Boot整合swagger2

在上一篇中我们围绕了Spring Boot 集成了RESTful API项目&#xff0c;但是我们在实际开发中&#xff0c;我们的一个RESTful API有可能就要服务多个不同的开发人员或者开发团队&#xff0c;包括不限于PC,安卓&#xff0c;IOS&#xff0c;甚至现在的鸿蒙OS&#xff0c;web开发等等…

buuctf_练[网鼎杯 2018]Fakebook

[网鼎杯 2018]Fakebook 文章目录 [网鼎杯 2018]Fakebook掌握知识解题思路关键paylaod 掌握知识 ​ SQL注入的联合注入&#xff1b;闭合类型的探查&#xff0c;本次是数字型闭合&#xff1b;SQL注入的读取文件的利用 解题思路 打开题目链接&#xff0c;发现主界面给了一些信息…

大数据-Storm流式框架(一)

一、storm介绍 Storm是个实时的、分布式以及具备高容错的计算系统 Storm进程常驻内存&#xff08;worker&#xff0c;supervisor&#xff0c;nimbus&#xff0c;ui&#xff0c;logviewer。。。&#xff09;Storm数据不经过磁盘&#xff0c;在内存中处理Twitter开源的分布式实时…

CSS基础框盒模型:打造炙手可热的网页布局!

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 ⭐ 专栏简介 &#x1f4d8; 文章引言 一、是…

老师们都在用的办公好物

现在还有老师不知道班级查询系统吗?各位老师们&#xff0c;向大家推荐一款超级实用的班级查询系统&#xff0c;帮你轻松管理学生信息&#xff0c;省去繁琐的手动操作&#xff0c;还能让学生们自主查询&#xff0c;简直是老师的福音&#xff01; 如果你在编程方面感到有些吃力&…

vscode推送gitee方法

有一套uni-app代码需要修改&#xff0c;版本控制使用vscode的git功能&#xff0c;远程库在gitee上。 1、设置vscode中git.exe路径 由于git使用了绿色便携版&#xff08;PortableGit-2.42.0.2-64-bit.7z.exe&#xff09;&#xff0c;vscode未识别到git安装路径&#xff0c;需要…

RTE2023大会来袭,声网宣布首创广播级4K超高清实时互动体验

10月24日&#xff0c;由声网和RTE开发者社区联合主办的RTE2023第九届实时互联网大会在北京举办&#xff0c;声网与众多RTE领域技术专家、产品精英、创业者、开发者一起&#xff0c;共同开启了以“智能高清”为主题的全新探讨。本届RTE大会将持续2天&#xff0c;开展1场主论坛及…

【路径规划】A*算法 Java实现

A*&#xff08;A-Star&#xff09;算法是一种广泛使用的寻路算法&#xff0c;尤其在计算机科学和人工智能领域。 算法思想 通过评估函数来引导搜索过程&#xff0c;从而找到从起始点到目标点的最短路径。评估函数通常包括两部分&#xff1a;一部分是已经走过的实际距离&#x…

「我在淘天做技术」双 11 背后的营销技术体系

作者&#xff1a;朱咏杰(小枫) 近期淘天集团秋季 2024 届校园招聘正式启动&#xff0c;预计将发放 2000 多个 offer&#xff0c;其中技术类岗位占比超过 50%。为了方便大家更真实地了解淘天技术的布局和现状&#xff0c;我们策划了「我在淘天做技术」系列&#xff0c;首次全面分…

科技资讯|苹果穿戴新专利,表带、服装等织物可变身柔性屏幕或扬声器

根据美国商标和专利局&#xff08;USPTO&#xff09;本周公示的清单&#xff0c;苹果公司获得了一项新的技术专利&#xff0c;可以在 Apple Watch 表带、服装等物品上&#xff0c;引入基于织物的柔性扬声器。 根据专利描述&#xff0c;通过在织物中嵌入声学组件&#xff08;例…

Makefile总结

一、Makefile用法及变量&#xff08;自定义变量、自动变量、隐含变量&#xff09; 一、Makefile的重要性 1、编译文件 2、正常编译&#xff0c;文件多的时候操作麻烦 3、决定能不能完成大型工程 二、Makefile的概述 1、自动化编译-makefile 编译效率&#xff1a;make编译…

01.MySQL(SQL分类及使用)

注意&#xff1a;DML只是进行增删改&#xff0c;DQL才有查询 分类全称说明DDLData Definition Language数据定义语言&#xff0c;用来定义数据库对象&#xff08;数据库&#xff0c;表&#xff0c;字段&#xff09;DMLData Manipulation Language数据操作语言&#xff0c;用来…

vue3的getCurrentInstance获取组件实例踩坑记录

一、getCurrentInstance基本用法 我们可以通过 getCurrentInstance这个函数来返回当前组件的实例对象,也就是当前vue这个实例对象 Vue2中&#xff0c;可以通过this来获取当前组件实例&#xff1b; Vue3中&#xff0c;在setup中无法通过this获取组件实例&#xff0c;console.lo…

ElasticSearch中关于Nasted嵌套查询的介绍:生动案例,通俗易懂,彻底吸收

题注&#xff1a;随着对ES接触的越来越深入&#xff0c;发现此前了解的ES知识点有点单薄&#xff0c;特此寻来ES知识点汇总成的一个思维导图&#xff0c;全面了解自己掌握了哪些&#xff0c;未掌握哪些。此外&#xff0c;作者斌并没有足够的精力学习ES全部的知识点&#xff0c;…

1024程序员节,飞桨星河社区开发者们一起闯关升级、玩转Prompt应用赢大奖~

1024&#xff0c;是属于每一位程序员/程序媛的节日~ 今年&#xff0c;飞桨给星河社区的开发者们也准备了“超级码力 碰撞未来”系列活动&#xff0c;和大家沉浸式玩转闯关冒险。 冲榜单 零代码打造爆款Prompt应用 飞桨AI Studio星河社区上线新版文心一言专区&#xff0c;帮助…