组合设计模式

news2024/12/23 10:18:34

一、组合模式

1、定义

组合模式(Composite Pattern)又称作整体-部分(Part-Whole)模式,其宗旨是通过将单个对象(叶子节点)和组织对象(树枝节点)用相同的接口进行表示,使得客户对单个对象和组合对象的使用具有一致性,属于结构型设计模式。

2、结构

(1)模式的结构

主要角色如下:

  • 抽象组成角色(Component):单个对象和组织对象的抽象基类或者接口,表示整个树形结构中的对象都属于同一种类型,用于访问和管理子节点。
  • 组织对象角色(Composite):树枝节点,用来存储子节点,并实现了组织接口中的操作方法。
  • 单个对象角色(Left):叶子节点,它没有子节点,它不需要实现组织接口中的操作方法。

(2)组合模式有两种

  • 透明组合模式: 组织接口中声明用来管理子对象的所有行为方法,好处就是树枝节点和叶子节点对外界没有区别,它们具备完全一致的行为接口,缺点时,叶子节点本身不具备组织接口的行为方法,所以实现它们是没有意义的。
  • 安全组合模式: 组织接口中不声明用来管理子对象的所有行为方法,所以叶子节点也就不需要去实现它们。而是在组织节点中声明用来管理子对象的所有行为方法。这样做由于不够透明,树枝节点和叶子节点将不具有相同的接口,客户端的调用需要做相应的判断,带来了不便。

3、优缺点

优点:

  • 清楚地定义各层次的复杂对象,表示对象的全部或部分层次。
  • 让客户端忽略了层次的差异,方便对整个层次结构进行控制。
  • 符合开闭原则。

缺点:

  • 限制类型时会较为复杂。
  • 使设计变得更加抽象。

4、使用场景

  • 希望客户端可以忽略组个对象与单个对象的差异。
  • 对象层次具备整体和部分,呈树形结构。

5、在框架源码中使用

  • Java中 HashMap 的 putAll方法,存储使用了一个静态内部类的数据Node[]。
  • Mybatis源码中解析Mapping文件中的 SQL语句时,使用到的 SqlNode类的作用非常关键。

二、模式的通用实现

1、透明组合模式

代码如下:

public class CompositePattern1 {
	public static void main(String[] args) {

		Component1 root = new Composite1("root");

		Component1 branch1 = new Composite1("branch1");
		Component1 branch2 = new Composite1("branch2");

		Component1 leaf1 = new Leaf1("leaf1");
		Component1 leaf2 = new Leaf1("leaf2");
		Component1 leaf3 = new Leaf1("leaf3");
		Component1 leaf4 = new Leaf1("leaf4");

		root.addChild(branch1);
		root.addChild(leaf3);
		branch1.addChild(leaf1);
		branch1.addChild(branch2);
		branch2.addChild(leaf2);
		branch2.addChild(leaf4);

		String display = root.display();
		System.out.println(display);
		System.out.println("===============");
		System.out.println("branch2.getChild(1).display() -> " + branch2.getChild(1).display());
		branch2.removeChild(leaf4);
		String display2 = root.display();
		System.out.println(display2);
	}
}

// 抽象组成角色
abstract class Component1 {

	protected String name;

	public Component1(String name) {
		this.name = name;
	}

	public abstract String display();

	public boolean addChild(Component1 component1) {
		throw new RuntimeException(" addChild 不支持");
	}

	public boolean removeChild(Component1 component1) {
		throw new RuntimeException(" removeChild 不支持");
	}

	public Component1 getChild(int index) {
		throw new RuntimeException(" getChild 不支持");
	}

}

// 组织对象角色
class Composite1 extends Component1 {

	private List<Component1> component1List;

	public Composite1(String name) {
		super(name);
		this.component1List = new ArrayList<Component1>();
	}

	@Override
	public String display() {
		StringBuilder sb = new StringBuilder(this.name);

		for (int i = 0; i < component1List.size(); i++) {
			Component1 component1 = component1List.get(i);
			sb.append("\n");
			sb.append(component1.display());
		}
		return sb.toString();
	}

	@Override
	public boolean addChild(Component1 component1) {
		return component1List.add(component1);
	}

	@Override
	public boolean removeChild(Component1 component1) {
		return component1List.remove(component1);
	}

	@Override
	public Component1 getChild(int index) {
		return component1List.get(index);
	}
}

// 单个对象角色
class Leaf1 extends Component1 {

	public Leaf1(String name) {
		super(name);
	}

	@Override
	public String display() {
		return this.name;
	}
}

在这里插入图片描述

2、安全组合模式

代码如下:

public class CompositePattern2 {
	public static void main(String[] args) {

		Composite2 root = new Composite2("root");

		Composite2 branch1 = new Composite2("branch1");
		Composite2 branch2 = new Composite2("branch2");

		Component2 leaf1 = new Leaf2("leaf1");
		Component2 leaf2 = new Leaf2("leaf2");
		Component2 leaf3 = new Leaf2("leaf3");
		Component2 leaf4 = new Leaf2("leaf4");

		root.addChild(branch1);
		root.addChild(leaf3);
		branch1.addChild(leaf1);
		branch1.addChild(branch2);
		branch2.addChild(leaf2);
		branch2.addChild(leaf4);

		String display = root.display();
		System.out.println(display);
		System.out.println("===============");
		System.out.println("branch2.getChild(1).display() -> " + branch2.getChild(1).display());
		branch2.removeChild(leaf4);
		String display2 = root.display();
		System.out.println(display2);
	}
}

// 抽象组成角色
abstract class Component2 {

	protected String name;

	public Component2(String name) {
		this.name = name;
	}

	public abstract String display();

}

// 组织对象角色
class Composite2 extends Component2 {

	private List<Component2> component2List;

	public Composite2(String name) {
		super(name);
		this.component2List = new ArrayList<Component2>();
	}

	@Override
	public String display() {
		StringBuilder sb = new StringBuilder(this.name);
		for (int i = 0; i < component2List.size(); i++) {
			sb.append("\n");
			Component2 component2 = component2List.get(i);
			sb.append(component2.display());
		}
		return sb.toString();
	}

	public boolean addChild(Component2 component2) {
		return component2List.add(component2);
	}

	public boolean removeChild(Component2 component2) {
		return component2List.remove(component2);
	}

	public Component2 getChild(int index) {
		return component2List.get(index);
	}
}

// 单个对象角色
class Leaf2 extends Component2 {

	public Leaf2(String name) {
		super(name);
	}

	@Override
	public String display() {
		return this.name;
	}
}

三、模式的应用实例

以文件系统为例,目录包含文件夹和文件。下面使用安全组合模式实现。

(1)目录:抽象组成角色

public abstract class Directory {

	protected String name;

	public Directory(String name) {
		this.name = name;
	}

	public abstract void show();
}

(2)文件夹:组织对象角色

public class Folder extends Directory {
	private List<Directory> dirList;

	private Integer depth;

	public Folder(String name, Integer depth) {
		super(name);
		this.depth = depth;
		dirList = new ArrayList<>();
	}

	public void list() {
		for (Directory dir : this.dirList) {
			System.out.println(dir.name);
		}
	}

	@Override
	public void show() {
		System.out.println(this.name);
		for (Directory dir : this.dirList) {
			if (this.depth != null) {
				for (Integer integer = 0; integer < this.depth; integer++) {
					System.out.print(" ");
				}
				for (Integer integer = 0; integer < this.depth; integer++) {
					if (integer == 0) {
						System.out.print("+");
					}
					System.out.print("-");
				}
			}
			dir.show();
		}
	}

	public boolean addChild(Directory directory) {
		return dirList.add(directory);
	}

	public boolean removeChild(Directory directory) {
		return dirList.remove(directory);
	}

	public Directory getChild(int index) {
		return dirList.get(index);
	}
}

(3)文件:单个对象角色

public class File extends Directory{

    public File(String name) {
        super(name);
    }

    @Override
    public void show() {
        System.out.println(this.name);
    }
}

(4)测试

	public static void main(String[] args) {
		Folder root = new Folder("root", 1);
		File dy = new File("抖音.exe");
		File qq = new File("QQ.exe");
		root.addChild(dy);
		root.addChild(qq);

		Folder office = new Folder("办公软件", 2);
		File word = new File("Word.exe");
		File ppt = new File("PPT.exe");
		File excel = new File("Excel.exe");
		office.addChild(word);
		office.addChild(ppt);
		office.addChild(excel);

		Folder devTools = new Folder("开发工具", 3);
		File idea = new File("idea.exe");
		File navicat = new File("navicat.exe");
		devTools.addChild(idea);
		devTools.addChild(navicat);

		office.addChild(devTools);
		root.addChild(office);

		System.out.println("========show方法======");
		root.show();
		System.out.println("========list方法======");
		root.list();
	}

在这里插入图片描述

– 求知若饥,虚心若愚。

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

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

相关文章

Egg 1. 快速开始 Quick Start 1.3 一步步 Step by Step 1.3.6 添加扩展 ~ 1.4 结论

Egg Egg 本文仅用于学习记录&#xff0c;不存在任何商业用途&#xff0c;如侵删 文章目录Egg1. 快速开始 Quick Start1.3 一步步 Step by Step1.3.6 添加扩展1.3.7 添加中间件1.3.8 添加配置1.3.9 添加单元测试1.4 结论1. 快速开始 Quick Start 1.3 一步步 Step by Step 1.3.…

求矩阵的行列式和逆矩阵 det()和inv()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 求矩阵的行列式和逆矩阵 det()和inv() [太阳]选择题 请问对以下Python代码说法错误的是&#xff1f; import numpy as np A np.array([[0,1],[2,3]]) print ("【显示】矩阵A") pr…

HedgeDoc的反向代理设置

因为 HedgeDoc 支持协同&#xff0c;所以很大可能性需要做反向代理设置&#xff0c;来让更多的人参与&#xff0c;但在上文 『Markdown协作编辑平台HedgeDoc』 中&#xff0c;老苏并未涉及到这部分&#xff0c;本文就是做这方面的补充。 老苏只研究了 nginx proxy manager 做反…

22个Vue 源码中的工具函数

前言 在 vue 源码中&#xff0c;封装了很多工具函数&#xff0c;学习这些函数&#xff0c;一方面学习大佬们的实现方式&#xff0c;另一方面是温习基础知识&#xff0c;希望大家在日常工作中&#xff0c;简单的函数也可以自己封装&#xff0c;提高编码能力。 本次涉及的工具函…

力扣(LeetCode)130. 被围绕的区域(C++)

dfs 只有和边界相连的 OOO 不会被 XXX 包围。遍历边界&#xff0c;搜索边界 OOO 的连通块&#xff0c;标记这些连通块。最后一次遍历矩阵&#xff0c;将标记的格子改回 OOO &#xff0c;其他格子改成 XXX &#xff0c;即为所求。 提示 : 可以用数组标记连通块&#xff0c;也可…

Java基于springboot+vue药店实名制买药系统 前后端分离

开发背景和意义 药品一直以来在人类生活中扮演着非常重要的角色&#xff0c;随着时代的发展&#xff0c;人们基本已经告别了那个缺医少药的年代&#xff0c;各大药房基本随处可以&#xff0c;但是很多时候因为没有时间或者在药店很难找到自己想要购买的药品&#xff0c;所以很…

元宇宙产业委叶毓睿:狂欢过后,万众期待的元宇宙怎么样了?

叶毓睿&#xff08;王学民/摄&#xff09; 自元宇宙出现在大众视野&#xff0c;大众对元宇宙的好奇和探索&#xff0c;从来没有停止过。当元宇宙的热度逐渐下降&#xff0c;我们不禁想要知道&#xff0c;狂欢过后&#xff0c;万众期待的元宇宙怎么样了&#xff1f; 近日&#x…

【吴恩达机器学习笔记】十一、聚类

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4e3;专栏定位&#xff1a;为学习吴恩达机器学习视频的同学提供的随堂笔记。 &#x1f4da;专栏简介&#xff1a;在这个专栏&#xff0c;我将整理吴恩达机器学习视频的所有内容的笔记&…

算法刷题入门线性表|单调栈

一、概念 1、栈的定义 栈 是仅限在 一端 进行 插入 和 删除 的 线性表。 栈 又被称为 后进先出 (Last In First Out) 的线性表&#xff0c;简称 LIFO 。 2、栈顶 栈 是一个线性表&#xff0c;我们把允许 插入 和 删除 的一端称为 栈顶。 3、栈底 和 栈顶 相对&#xff0c;另一端…

java计算机毕业设计ssm软件学院社团管理系统l62lq(附源码、数据库)

java计算机毕业设计ssm软件学院社团管理系统l62lq&#xff08;附源码、数据库&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#…

[附源码]计算机毕业设计基于SpringBoot+Vue的健身房会员系统的设计与实现

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Linux系统( Centos 7) 配置与管理Apache服务器实例详细步骤

Linux系统&#xff08; Centos 7&#xff09; 配置与管理Apache服务器实例详细步骤 服务器centos7-1 1.配置网络。 [rootcentos7 ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens33 TYPEEthernet PROXY_METHODnone BROWSER_ONLYno BOOTPROTOstatic DEFROUTEyes IPV…

【WPF】附加事件

【WPF】附加事件什么是附加事件附加事件用法Microsoft 官方文档附加事件案例定义自定义控件注册使用附加事件什么是附加事件 Microsoft 官方概述&#xff1a;   附加事件可用于在非元素类中定义新的 路由事件 &#xff0c;并在树中的任何元素上引发该事件。 为此&#xff0c;…

【WebRTC】拥塞控制 GCC 类图

GoogCcNetworkController : 整个 congestion_controller 模块的中心类&#xff0c;是对外的接口 AcknowledgedBitrateEstimatorInterface AcknowledgedBitrateEstimator : 估算当前的吞吐量。 BitrateEstimator : 使用滑动窗口 卡尔曼滤波计算当前发送吞吐量。 RobustThro…

【Android App】实战项目之仿拼多多的直播带货(附源码和演示 超详细必看)

需要源码请点赞关注收藏后评论区留言私信~~~ 近年来电商业态发生了不小的改变&#xff0c;传统的电商平台把商品分门别类&#xff0c;配上精美的图文说明供消费者挑选&#xff0c;新潮的电商平台则请来明星网红&#xff0c;开启直播秀向广大粉丝推销商品&#xff0c;往往一场直…

微服务应对雪崩的容错方案

引言 书接上篇 微服务绕不过的坎-服务雪崩 &#xff0c;玩微服务不可避免的问题&#xff1a;服务雪崩&#xff0c;那为了应付服务雪崩问题&#xff0c;需要做啥预防性操作呢&#xff1f;答案是&#xff1a;做好容错保护 容错方案 前面说了&#xff0c;要防止雪崩的扩散&…

[附源码]计算机毕业设计springboot疫情期间小学生作业线上管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Android自定义视图

View 自定义视图主要涉及四个方面&#xff1a;绘图、交互、性能和封装 绘图 主要涉及两个对象&#xff1a;画布&#xff08;Canvas&#xff09;和画笔&#xff08;Paint&#xff09;&#xff0c;画布主要解决画什么的问题&#xff0c;在画布上可以绘制各种各样的图形&#x…

《CTFshow - Web入门》04. Web 31~40

Web 31~40web31知识点题解web32知识点题解web33知识点题解web34知识点题解web35知识点题解web36知识点题解web37知识点题解web38知识点题解web39知识点题解web40知识点题解web31 知识点 这里依旧可以用到 web29 的方法&#xff1a; 嵌套eval逃逸参数 当然&#xff0c;能多学…

# 智慧社区管理系统-基础信息管理-06抄表管理

一后端 1:entity package com.woniu.community.entity;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;Data AllArgsConstructor NoArgsConstructor public class Records {private int id;private int typeId;private Double num…