Gof23设计模式之组合模式

news/2024/11/16 14:52:26/

1.定义

​组合模式又名部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
在这里插入图片描述

2.结构

组合模式主要包含三种角色:

  • 抽象根节点(Component):定义系统各层次对象的共有方法和属性,可以预先定义一些默认行为和属性。
  • 树枝节点(Composite):定义树枝节点的行为,存储子节点,组合树枝节点和叶子节点形成一个树形结构。
  • 叶子节点(Leaf):叶子节点对象,其下再无分支,是系统层次遍历的最小单位。

3.实现

我们在访问别的一些管理系统时,经常可以看到类似的菜单。一个菜单可以包含菜单项(菜单项是指不再包含其他内容的菜单条目),也可以包含带有其他菜单项的菜单,因此使用组合模式描述菜单就很恰当,我们的需求是针对一个菜单,打印出其包含的所有菜单以及菜单项的名称。
在这里插入图片描述

/*** @author 晓风残月Lx* @date 2023/7/12 16:38*      菜单组件 (抽象根节点)*/
public abstract class MenuComponent {// 菜单组件的名称protected String name;// 菜单组件的层级protected int level;// 添加子菜单public void add(MenuComponent menuComponent) {throw new UnsupportedOperationException();}// 移除子菜单public void remove(MenuComponent menuComponent) {throw new UnsupportedOperationException();}// 获取指定的子菜单public MenuComponent getChild(int index) {throw new UnsupportedOperationException();}// 获取菜单或者菜单项的名称public String getName() {return name;}// 打印菜单名称的方法(包含子菜单和子菜单项)public abstract void print();}import java.util.ArrayList;
import java.util.List;/*** @author 晓风残月Lx* @date 2023/7/12 16:43*      菜单类(树枝节点)*/
public class Menu extends MenuComponent {// 菜单可以有多个子菜单或者子菜单项private List<MenuComponent> menuComponentList = new ArrayList<MenuComponent>();public Menu(String name, int level) {this.name = name;this.level = level;}@Overridepublic void add(MenuComponent menuComponent) {menuComponentList.add(menuComponent);}@Overridepublic void remove(MenuComponent menuComponent) {menuComponentList.remove(menuComponent);}@Overridepublic MenuComponent getChild(int index) {return menuComponentList.get(index);}@Overridepublic void print() {// 打印菜单名称for(int i = 0; i < level; i++) {System.out.print("--");}System.out.println(name);// 打印子菜单名称或者子菜单项名称for (MenuComponent menuComponent : menuComponentList) {menuComponent.print();}}
}/*** @author 晓风残月Lx* @date 2023/7/12 16:47*      菜单项类(叶子节点)*/
public class MenuItem extends MenuComponent {public MenuItem(String name, int level) {this.name = name;this.level = level;}@Overridepublic void print() {for(int i = 0; i < level; i++) {System.out.print("--");}// 打印菜单项的名称System.out.println(name);}
}/*** @author 晓风残月Lx* @date 2023/7/12 16:49*/
public class Client {public static void main(String[] args) {// 创建菜单树MenuComponent menu1 = new Menu("菜单管理", 2);menu1.add(new MenuItem("页面菜单", 3));menu1.add(new MenuItem("展开菜单", 3));menu1.add(new MenuItem("编辑菜单", 3));MenuComponent menu2 = new Menu("权限管理", 2);menu2.add(new MenuItem("页面访问", 3));menu2.add(new MenuItem("提交保存", 3));MenuComponent menu3 = new Menu("角色管理", 2);menu3.add(new MenuItem("新增角色", 3));// 创建一级菜单MenuComponent component = new Menu("系统管理", 1);component.add(menu1);component.add(menu2);component.add(menu3);component.print();}}

在这里插入图片描述

4.组合模式的分类

在使用组合模式时,根据抽象构件类的定义形式,我们可将组合模式分为透明组合模式和安全组合模式两种形式。

  • 透明组合模式

    透明组合模式中,抽象根节点角色中声明了所有用于管理成员对象的方法,比如在示例中 MenuComponent 声明了 addremovegetChild 方法,这样做的好处是确保所有的构件类都有相同的接口。透明组合模式也是组合模式的标准形式。

    透明组合模式的缺点是不够安全,因为叶子对象和容器对象在本质上是有区别的,叶子对象不可能有下一个层次的对象,即不可能包含成员对象,因此为其提供 add()、remove() 等方法是没有意义的,这在编译阶段不会出错,但在运行阶段如果调用这些方法可能会出错(如果没有提供相应的错误处理代码)

  • 安全组合模式

    在安全组合模式中,在抽象构件角色中没有声明任何用于管理成员对象的方法,而是在树枝节点 Menu 类中声明并实现这些方法。安全组合模式的缺点是不够透明,因为叶子构件和容器构件具有不同的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,因此客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件。

5.优点

  • 组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制。
  • 客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码。
  • 在组合模式中增加新的树枝节点和叶子节点都很方便,无须对现有类库进行任何修改,符合“开闭原则”。
  • 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子节点和树枝节点的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单。

6.使用场景

组合模式正是应树形结构而生,所以组合模式的使用场景就是出现树形结构的地方。比如:文件目录显示,多级目录呈现等树形结构数据的操作。


http://www.ppmy.cn/news/1010156.html

相关文章

MySql的Windows安装指南

目录 一、MySQL的4大版本 二、软件的下载 三、MySQL8.0 版本的安装 四、配置MySQL8.0 五、配置MySQL8.0 环境变量 六、登录验证 一、MySQL的4大版本 MySQL Community Server 社区版本&#xff0c;开源免费&#xff0c;自由下载&#xff0c;但不提供官方技术支持&#xff…

Detecting Everything in the Open World: Towards Universal Object Detection

1. 论文简介 论文题目《Detecting Everything in the Open World: Towards Universal Object Detection》发表情况&#xff0c;CVPR2023[论文地址][https://arxiv.org/pdf/2303.11749.pdf][代码地址][https://github.com/zhenyuw16/UniDetector] 2.背景与摘要 本文旨在解决通…

Effective Java笔记(20)接口优于抽象类

Java提供了两种机制&#xff0c;可以用来定义允许多个实现的类型&#xff1a;接口和抽象类。自从Java 8为继承引入了缺省方法( default method)&#xff0c;这两种机制都允许为某些实例方法提供实现。主要的区别在于&#xff0c;为了实现由抽象类定义的类型&#xff0c;类必须成…

c++实现Qt信号和槽机制

文章目录 简介信号槽信号与槽的连接 特点观察者模式定义观察者模式结构图 实现简单的信号和槽 简介 信号槽机制与Windows下消息机制类似&#xff0c;消息机制是基于回调函数&#xff0c;Qt中用信号与槽来代替函数指针&#xff0c;使程序更安全简洁。  信号和槽机制是 Qt 的核心…

Python-面向对象:面向对象、成员方法 、类和对象、构造方法、魔术方法、封装、继承、类型注解、多态(抽象类(接口))

版本说明 当前版本号[20230806]。 版本修改说明20230806初版 目录 文章目录 版本说明目录知识总览图面向对象初识对象生活中数据的组织程序中数据的组织使用对象组织数据 成员方法类的定义和使用成员变量和成员方法成员方法的定义语法注意事项 类和对象现实世界的事物和类使…

六、ESP32数码管显示数字

1. 本节课的成功 2. 数码管 为什么会亮呢? 答:里面就是LED灯

leetcode 1290.二进制链表转整数

⭐️ 题目描述 &#x1f31f; leetcode链接&#xff1a;二进制链表转整数 ps&#xff1a; 1 0 1 (0 << 1) 1 0 1 1 (1 << 1) 0 2 0 2 (2 << 1) 1 4 1 5代码&#xff1a; int getDecimalValue(struct ListNode* head) {int ans 0;while(head !…

【IC萌新虚拟项目】sanity case与寄存器测试case通包

关于整个虚拟项目,请参考: 【HISI IC萌新虚拟项目】Package Process Unit项目全流程目录_尼德兰的喵的博客-CSDN博客 前言 上一篇文章中千辛万苦的把验证环境搭了起来,然后寄存器访问直接就挂了,之后这一周就慢慢的调bug终于完成了sanity通包。 冒烟测试 什么是验证的冒…