Python设计模式 - 组合模式

定义

组合模式(Composite Pattern) 是一种结构型设计模式,主要意图是将对象组织成树形结构以表示"部分-整体"的层次结构。这种模式能够使客户端统一对待单个对象和组合对象,从而简化了客户端代码。

组合模式有透明组合模式和安全组合模式两种,下面分别介绍这两种模式。

透明组合模式

结构

在这里插入图片描述

  • 组件(Component):组件是组合中的抽象类或接口,它声明了叶子节点和组合节点的公共接口,以确保客户端可以统一对待单个对象和组合对象。组件通常包含一些操作方法,如添加子节点、删除子节点、获取子节点等。
  • 叶子节点(Leaf):叶子节点是组合中的叶子对象,它没有子节点。叶子节点实现了组件接口,并提供了具体的操作方法。叶子节点表示组合中的最小单元,是组合结构中不可再分的基本元素。
  • 组合节点(Composite):组合节点是组合中的复合对象,它可以包含其他组件作为子节点。组合节点也实现了组件接口,并提供了与叶子节点相同的操作方法。组合节点表示组合结构中的内部节点,可以包含其他子节点。

应用场景

  1. 树形结构表示:当你的问题领域可以自然地表示为树形结构时,透明组合模式是一个很好的选择。例如,文件系统、组织结构等都可以使用透明组合模式来表示。
  2. 部分-整体关系:当你的问题领域中存在明显的部分-整体关系时,透明组合模式可以帮助你更好地表示和处理这种关系。例如,产品和其部件、图形和其组成元素等都可以使用透明组合模式来表示。

优缺点

优点:

  1. 简化客户端代码:透明组合模式使客户端能够统一对待单个对象和组合对象,从而简化了客户端代码。客户端不需要关心对象的具体类型,而是统一使用相同的接口来操作对象。
  2. 灵活性:透明组合模式允许你在运行时动态地添加、移除和修改对象的组合结构,从而提供了更大的灵活性。你可以方便地调整对象之间的层次关系,以满足不同的需求。
  3. 可扩展性:由于透明组合模式将叶子节点和组合节点都视为相同类型的对象,因此很容易添加新的节点类型,而不会影响到现有的代码。这提高了系统的可扩展性。

缺点:

  1. 限制性:透明组合模式要求叶子节点和组合节点实现相同的接口,这可能会限制叶子节点和组合节点的设计和扩展。有时候,这种限制可能会影响到系统的设计和灵活性。
  2. 性能问题:组合模式可能会带来一些性能问题,特别是在处理大型的对象组合结构时的遍历性能。这包括遍历性能、内存占用等方面的问题,可能会影响系统的性能表现。

代码示例

from abc import ABC, abstractmethod


# 抽象组件类
class Component(ABC):
    @abstractmethod
    def add(self, component):
        pass

    @abstractmethod
    def remove(self, component):
        pass

    @abstractmethod
    def scan(self):
        pass


# 叶子节点类:文件
class File(Component):
    def __init__(self, name):
        self.name = name

    def add(self, component):
        raise NotImplementedError('文件不支持添加子组件')

    def remove(self, component):
        raise NotImplementedError('文件不支持移除子组件')

    def scan(self):
        print("正在扫描文件:", self.name)


# 组合节点类:文件夹
class Folder(Component):
    def __init__(self, name):
        self.name = name
        self.children = []

    def add(self, component):
        self.children.append(component)

    def remove(self, component):
        self.children.remove(component)

    def scan(self):
        print("正在扫描文件夹:", self.name)
        for child in self.children:
            child.scan()


# 客户端代码
if __name__ == "__main__":
    # 创建文件和文件夹对象
    file1 = File("file1.txt")
    file2 = File("file2.txt")
    folder1 = Folder("folder1")
    folder2 = Folder("folder2")

    # 将文件添加到文件夹中
    folder1.add(file1)
    folder2.add(file2)

    # 将文件夹添加到文件夹中
    root_folder = Folder("root")
    root_folder.add(folder1)
    root_folder.add(folder2)

    # 扫描根文件夹
    root_folder.scan()

安全组合模式

安全组合模式是组合模式的一种变体,它与透明组合模式相比,区别在于它将管理子节点的方法从抽象组件中移除,使得叶子节点和组合对象的接口不再相同,从而更加安全。

结构

在这里插入图片描述

  • Component(组件):定义了叶子节点和组合对象的公共接口,可以包含一些默认的行为。这个接口通常包括操作方法,如 operation(),但不包括管理子节点的方法。
  • Leaf(叶子节点):表示组合中的叶子对象,没有子节点,实现了 Component 接口。通常,叶子节点执行最终的操作。
  • Composite(组合对象):表示组合中的容器对象,可以包含子节点,也实现了 Component 接口。它负责管理子节点,包括添加、删除和获取子节点等操作。

应用场景

使用场景和透明组合模式一样:

  1. 树形结构表示:当你的问题领域可以自然地表示为树形结构时,透明组合模式是一个很好的选择。例如,文件系统、组织结构等都可以使用透明组合模式来表示。
  2. 部分-整体关系:当你的问题领域中存在明显的部分-整体关系时,透明组合模式可以帮助你更好地表示和处理这种关系。例如,产品和其部件、图形和其组成元素等都可以使用透明组合模式来表示。

如何选择使用透明组合模式还是安全组合模式:

对于简单的情况和对接口一致性要求较高的情况,透明组合模式可能更为适用。而对于复杂的情况和对接口分离性要求较高的情况,安全组合模式可能更为合适,因为它可以明确区分组合对象和叶子对象的接口,提高了安全性和灵活性。

优缺点

优点:

  1. 接口隔离性强:安全组合模式明确区分了组合对象和叶子对象的接口,使得客户端只能通过组合对象来操作子节点,从而提高了接口的隔离性。
  2. 安全性高:由于叶子对象的接口不再包含管理子节点的方法,安全组合模式可以更好地防止客户端直接对叶子对象进行不安全的操作,从而提高了系统的安全性。
  3. 灵活性增强:安全组合模式允许组合对象和叶子对象的接口可以根据实际需求进行灵活设计,使得系统更容易扩展和维护。

缺点:

  1. 使用复杂度增加:相比于透明组合模式,安全组合模式引入了额外的接口和方法,可能会增加系统的使用复杂度和理解成本。
  2. 性能问题:组合模式可能会带来一些性能问题,特别是在处理大型的对象组合结构时的遍历性能。这包括遍历性能、内存占用等方面的问题,可能会影响系统的性能表现。

代码示例

from abc import ABC, abstractmethod


# 抽象组件类
class Component(ABC):
    @abstractmethod
    def scan(self):
        pass


# 叶节点类:文件
class File(Component):
    def __init__(self, name):
        self.name = name

    def scan(self):
        print("正在扫描文件:", self.name)


# 组合节点类:文件夹
class Folder(Component):
    def __init__(self, name):
        self.name = name
        self.children = []

    def add(self, component):
        self.children.append(component)

    def remove(self, component):
        self.children.remove(component)

    def scan(self):
        print("正在扫描文件夹:", self.name)
        for child in self.children:
            child.scan()


# 客户端代码
if __name__ == "__main__":
    # 创建文件和文件夹对象
    file1 = File("file1.txt")
    file2 = File("file2.txt")
    folder1 = Folder("folder1")
    folder2 = Folder("folder2")

    # 将文件添加到文件夹中
    folder1.add(file1)
    folder2.add(file2)

    # 将文件夹添加到文件夹中
    root_folder = Folder("root")
    root_folder.add(folder1)
    root_folder.add(folder2)

    # 扫描根文件夹
    root_folder.scan()

参考

《设计模式的艺术》

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

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

相关文章

19.Word:小马-校园科技文化节❗【36】

目录 题目​ NO1.2.3 NO4.5.6 NO7.8.9 NO10.11.12索引 题目 NO1.2.3 布局→纸张大小→页边距:上下左右插入→封面:镶边→将文档开头的“黑客技术”文本移入到封面的“标题”控件中,删除其他控件 NO4.5.6 标题→原文原文→标题 正文→手…

一文讲解Java中Object类常用的方法

在Java中,经常提到一个词“万物皆对象”,其中的“万物”指的是Java中的所有类,而这些类都是Object类的子类; Object主要提供了11个方法,大致可以分为六类: 对象比较: public native int has…

多项日常使用测试,带你了解如何选择AI工具 Deepseek VS ChatGpt VS Claude

多项日常使用测试,带你了解如何选择AI工具 Deepseek VS ChatGpt VS Claude 注:因为考虑到绝大部分人的使用,我这里所用的模型均为免费模型。官方可访问的。ChatGPT这里用的是4o Ai对话,编程一直以来都是人们所讨论的话题。Ai的出现…

Linux下学【MySQL】表的必备操作( 配实操图和SQL语句)

绪论​ “Patience is key in life (耐心是生活的关键)”。本章是MySQL中非常重要且基础的知识----对表的操作。再数据库中表是存储数据的容器,我们通过将数据填写在表中,从而再从表中拿取出来使用,本章主要讲到表的增…

【Java数据结构】了解排序相关算法

基数排序 基数排序是桶排序的扩展,本质是将整数按位切割成不同的数字,然后按每个位数分别比较最后比一位较下来的顺序就是所有数的大小顺序。 先对数组中每个数的个位比大小排序然后按照队列先进先出的顺序分别拿出数据再将拿出的数据分别对十位百位千位…

【全栈】SprintBoot+vue3迷你商城(9)

【全栈】SprintBootvue3迷你商城(9) 往期的文章都在这里啦,大家有兴趣可以看一下 后端部分: 【全栈】SprintBootvue3迷你商城(1) 【全栈】SprintBootvue3迷你商城(2) 【全栈】Spr…

php-phar打包避坑指南2025

有很多php脚本工具都是打包成phar形式,使用起来就很方便,那么如何自己做一个呢?也找了很多文档,也遇到很多坑,这里就来总结一下 phar安装 现在直接装yum php-cli包就有phar文件,很方便 可通过phar help查看…

【数据结构】_顺序表

目录 1. 概念与结构 1.1 静态顺序表 1.2 动态顺序表 2. 动态顺序表实现 2.1 SeqList.h 2.2 SeqList.c 2.3 Test_SeqList.c 3. 顺序表性能分析 线性表是n个具有相同特性的数据元素的有限序列。 常见的线性表有:顺序表、链表、栈、队列、字符串等&#xff1b…

OPencv3.4.1安装及配置教程

来到GitHub上opencv的项目地址 https://github.com/opencv/opencv/releases/tag/3.4.1 以上资源包都是 OpenCV 3.4.1 版本相关资源,它们的区别如下: (1). opencv-3.4.1-android-sdk.zip:适用于 Android 平台的软件开发工具包(SDK…

世上本没有路,只有“场”et“Bravo”

楔子:电气本科“工程电磁场”电气研究生课程“高等电磁场分析”和“电磁兼容”自学”天线“、“通信原理”、“射频电路”、“微波理论”等课程 文章目录 前言零、学习历程一、Maxwells equations1.James Clerk Maxwell2.自由空间中传播的电磁波3.边界条件和有限时域…

ZYNQ-IP-AXI-GPIO

AXI GPIO 可以将 PS 端的一个 AXI 4-Lite 接口转化为 GPIO 接口,并且可以被配置为单端口或双端口,每个通道的位宽可以独立配置。 通过使能三态门可以将端口动态地配置为输入或输出。 AXIGPIO 是 ZYNQ PL 端的一个 IP 核,可以将 AXI-Lite Mas…

20.Word:小谢-病毒知识的科普文章❗【38】

目录 题目​ NO1.2.3文档格式 NO4.5 NO6.7目录/图表目录/书目 NO8.9.10 NO11索引 NO12.13.14 每一步操作完,确定之后记得保存最后所有操作完记得再次删除空行 题目 NO1.2.3文档格式 样式的应用 选中应用段落段落→开始→选择→→检查→应用一个一个应用ctr…

为什么应用程序是特定于操作系统的?[计算机原理]

你把WINDOWS程序复制到MAC上使用,会发现无法运行。你可能会说,MAC是arm处理器,而WINDWOS是X86 处理器。但是在2019年,那时候MAC电脑还全是Intel处理器,在同样的X86芯片上,运行MAC和WINDOWS 程序还是无法互相…

LigerUI在MVC模式下的响应原则

LigerUI是基于jQuery的UI框架,故他也是遵守jQuery的开发模式,但是也具有其特色的侦听函数,那么当LigerUI作为View层的时候,他所发送后端的必然是表单的数据,在此我们以俩个div为例: {Layout "~/View…

BurpSuite--暴力破解

一.弱口令 1. 基本概念 介绍:弱口令(weak password)是指那些容易被他人猜测或通过工具破解的密码。虽然弱口令没有严格的定义,但通常它指的是由简单的数字、字母、常用词语或规律性组合构成的密码。 特点: 密码容易被…

深入探讨防抖函数中的 this 上下文

深入剖析防抖函数中的 this 上下文 最近我在研究防抖函数实现的时候,发现一个耗费脑子的问题,出现了令我困惑的问题。接下来,我将通过代码示例,深入探究这些现象背后的原理。 示例代码 function debounce(fn, delay) {let time…

【PostgreSQL内核学习 —— (WindowAgg(一))】

WindowAgg 窗口函数介绍WindowAgg理论层面源码层面WindowObjectData 结构体WindowStatePerFuncData 结构体WindowStatePerAggData 结构体eval_windowaggregates 函数update_frameheadpos 函数 声明:本文的部分内容参考了他人的文章。在编写过程中,我们尊…

RocketMQ消息是如何存储的?

大家好,我是锋哥。今天分享关于【RocketMQ消息是如何存储的?】面试题。希望对大家有帮助; RocketMQ消息是如何存储的? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 RocketMQ 使用了一个高性能、分布式的消息存储架构…

MongoDB平替数据库对比

背景 项目一直是与实时在线监测相关,特点数据量大,读写操作大,所以选用的是MongoDB。但按趋势来讲,需要有一款国产数据库可替代,实现信创要求。选型对比如下 1. IoTDB 这款是由清华大学主导的开源时序数据库&#x…

电力晶体管(GTR)全控性器件

电力晶体管(Giant Transistor,GTR)是一种全控性器件,以下是关于它的详细介绍:(模电普通晶体管三极管进行对比学习) 基本概念 GTR是一种耐高电压、大电流的双极结型晶体管(BJT&am…