设计模式:组合模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)

简介:

组合模式,它是一种用于处理树形结构、表示“部分-整体”层次结构的设计模式。它允许你将对象组合成树形结构,以表示部分和整体的关系。这种模式的主要目的是简化客户端代码,并使客户端以一致的方式处理单个对象和组合对象。

在组合模式中,抽象根节点(Component)定义了系统各层次对象的公有方法和属性,可以预先定义一些默认行为和属性。树枝节点(Composite)定义了树枝节点的行为,存储子节点,组合树枝节点和叶子节点形成一个树形结构。叶子节点(Leaf)是系统层次遍历的最小单位。

组合模式的使用场景包括但不限于以下几种情况:

1、表示部分-整体层次结构:组合模式适用于需要处理部分-整体关系的场景,例如文件系统中的文件夹和文件之间的关系。通过组合模式,可以将文件夹和文件组合在一起,形成一个树形结构,方便用户进行操作和管理。
2、处理树形结构:组合模式适用于处理树形结构的情况,例如表达式树、决策树等。在这些场景中,可以将对象组合成树形结构,以表示部分和整体的关系,方便对整个树形结构进行操作和管理。
3、简化客户端代码:组合模式可以简化客户端代码,使得客户端只需要面对一致的对象而不用考虑整体部分或叶子节点的问题。通过组合模式,客户端可以将对组合对象的操作委托给其子对象,而无需知道具体执行的是单个对象还是整个组合。
4、提高系统的灵活性和可扩展性:组合模式可以使得系统的设计更加灵活和可扩展。通过组合模式,可以轻松地添加新的对象类型,而不需要修改现有的代码。同时,组合模式还可以使得系统更容易适应变化和扩展,提高系统的可维护性和可重用性。

总之,组合模式适用于需要处理部分-整体关系的场景,以及需要简化客户端代码、提高系统灵活性和可扩展性的情况。在使用组合模式时,需要注意抽象化、封装和继承等问题,以保证代码的正确性和可维护性。

组合模式的创建步骤如下:
1、创建抽象组件类(Component),该类通常包含一些共有的属性和方法,例如添加、删除子节点等。
2、创建具体组件类(Leaf),该类继承自抽象组件类,并实现具体的业务逻辑。
3、创建复合组件类(Composite),该类同样继承自抽象组件类,并添加对子节点的管理操作,例如添加、删除子节点等。
4、在复合组件类中实现一些公共操作,例如遍历整个树形结构等。
5、客户端代码通过调用复合组件类的操作来管理整个树形结构,而无需关心具体的叶子节点或复合组件类的内部实现细节。

需要注意的是,在实际应用中,需要根据具体需求选择是否使用组合模式,并注意处理好对象组合的层次关系,以及保证代码的正确性和可维护性。

组合模式的优点,主要包括:
1、清楚地定义分层次的复杂对象,表示对象的全部或部分层次。这使得增加新构件也更容易,因为可以在已有的层次结构中添加新的节点。
2、客户端调用简单。客户端可以一致地使用组合结构或其中单个对象,而不必关心处理的是单个对象还是整个组合结构,这简化了客户端代码。
3、更容易在组合体内加入对象构件。在组合模式中,增加新的容器构件和叶子构件都很方便,无需对现有类库进行任何修改,符合"开闭原则"。
4、为树型结构的面向对象实现提供了一种灵活的解决方案。通过叶子对象和容器对象的递归组合,可以形成复杂的树型结构,但对树型结构的控制却非常简单。
总的来说,组合模式能够简化客户端代码,并使得增加新构件和形成复杂树形结构更加容易。同时,它还提供了一种灵活的解决方案,使得面向对象实现更加高效。

组合模式的缺点,主要包括:
1、设计较复杂。由于组合模式需要定义抽象组件类、具体组件类和复合组件类,以及它们之间的层次关系和操作,因此设计起来相对复杂。
2、不容易限制容器中的构件。在组合模式中,容器中的构件可以自由地添加、删除和组合,这可能导致一些问题,例如无限递归、内存泄漏等。
3、不容易用继承的方法来增加构件的新功能。由于组合模式采用递归组合的方式,而不是通过继承来增加构件的新功能,因此需要手动添加新的构件,这可能会增加代码的复杂度和维护成本。

示例:

一、C#组合模式

以下是一个示例,展示了如何在C#中实现组合模式:

首先,定义一个抽象组件类(Component),该类通常包含一些共有的属性和方法,例如添加、删除子节点等。

public abstract class Component  
{  public virtual void Operation()  {  // 具体实现留给子类去完成  }  
}

然后,创建具体组件类(Leaf),该类继承自抽象组件类,并实现具体的业务逻辑。

public class Leaf : Component  
{  public override void Operation()  {  // 具体实现留给子类去完成  }  
}

接下来,创建复合组件类(Composite),该类同样继承自抽象组件类,并添加对子节点的管理操作,例如添加、删除子节点等。

public class Composite : Component, ICollection<Component>  
{  private List<Component> children = new List<Component>();  public void Add(Component component)  {  children.Add(component);  }  public void Remove(Component component)  {  children.Remove(component);  }  public override void Operation()  {  foreach (var child in children)  {  child.Operation(); // 递归调用子节点的Operation方法  }  }  
}

最后,在客户端代码中,可以通过创建复合组件类的实例来管理整个树形结构,而无需关心具体的叶子节点或复合组件类的内部实现细节。

public class Client {  public void test() { Composite root = new Composite(); // 创建根节点  Leaf leaf1 = new Leaf(); // 创建叶子节点1  Leaf leaf2 = new Leaf(); // 创建叶子节点2  Composite composite1 = new Composite(); // 创建复合节点1  Composite composite2 = new Composite(); // 创建复合节点2  // 将节点添加到相应的复合节点中,或者直接添加到根节点下  root.Add(leaf1);   root.Add(leaf2);   composite1.Add(leaf1);   composite2.Add(leaf2);   root.Add(composite1);   root.Add(composite2);   // 调用根节点的Operation方法,将递归遍历整个树形结构并执行相应的操作  root.Operation();}
}

二、java组合模式

组合模式通常通过以下方式实现:

//首先,定义一个抽象组件类(Component),该类通常包含一些共有的属性和方法,例如添加、删除子节点等。
public abstract class Component {  public void add(Component component) {  // 具体实现留给子类去完成  }  public void remove(Component component) {  // 具体实现留给子类去完成  }  public void operation() {  // 具体实现留给子类去完成  }  
}
//然后,创建具体组件类(Leaf),该类继承自抽象组件类,并实现具体的业务逻辑。
public class Leaf extends Component {  @Override  public void operation() {  // 具体实现留给子类去完成  }  
}
//接下来,创建复合组件类(Composite),该类同样继承自抽象组件类,并添加对子节点的管理操作,例如添加、删除子节点等。
public class Composite extends Component {  private List<Component> children = new ArrayList<>();  @Override  public void add(Component component) {  children.add(component);  }  @Override  public void remove(Component component) {  children.remove(component);  }  @Override  public void operation() {  for (Component child : children) {  child.operation(); // 递归调用子节点的operation方法  }  }  
}
//最后,在客户端代码中,可以通过创建复合组件类的实例来管理整个树形结构,而无需关心具体的叶子节点或复合组件类的内部实现细节。
public class Client {  public static void main(String[] args) {Composite root = new Composite(); // 创建根节点  Leaf leaf1 = new Leaf(); // 创建叶子节点1  Leaf leaf2 = new Leaf(); // 创建叶子节点2  Composite composite1 = new Composite(); // 创建复合节点1  Composite composite2 = new Composite(); // 创建复合节点2  // 将节点添加到相应的复合节点中,或者直接添加到根节点下  root.add(leaf1);   root.add(leaf2);   composite1.add(leaf1);   composite2.add(leaf2);   root.add(composite1);   root.add(composite2);   // 调用根节点的operation方法,将递归遍历整个树形结构并执行相应的操作  root.operation();}
}

三、javascript组合模式

在JavaScript中,组合模式的实现方式如下:

//定义一个抽象组件类
class Component {  constructor(name) {  this.name = name;  this.children = [];  }  addChild(component) {  this.children.push(component);  }  removeChild(component) {  this.children = this.children.filter(child => child !== component);  }  printTree() {  console.log(this.name);  this.children.forEach(child => child.printTree());  }  
}
//创建具体组件类
class Leaf extends Component {  constructor(name) {  super(name);  }  printLeaf() {  console.log(`${this.name} (Leaf)`);  }  
}
//创建复合组件类
class Composite extends Component {  constructor(name) {  super(name);  }  addChild(component) {  if (component instanceof Leaf) {  super.addChild(component);  } else if (component instanceof Composite) {  component.children.forEach(child => this.addChild(child));  } else {  throw new Error('Invalid component type');  }  }  
}

四、C++组合模式

以下是在C++中实现组合模式:

#include <iostream>  class Component {  
public:  virtual void operation() = 0;  
};  class Leaf : public Component {  
public:  Leaf(int value) : m_value(value) {}  void operation() override { std::cout << "Leaf operation: " << m_value << std::endl; }  
private:  int m_value;  
};  class Composite : public Component {  
public:  Composite() {}  void addChild(Component* child) { m_children.push_back(child); }  void removeChild(Component* child) { m_children = m_children.erase(std::remove(m_children.begin(), m_children.end(), child)); }  void operation() override {  for (auto child : m_children) {  child->operation();  }  }  
private:  std::vector<Component*> m_children;  
};  int main() {  Composite* root = new Composite();  Leaf* leaf1 = new Leaf(1);  Leaf* leaf2 = new Leaf(2);  Composite* composite1 = new Composite();  Composite* composite2 = new Composite();  root->addChild(leaf1);  root->addChild(leaf2);  composite1->addChild(leaf1);  composite2->addChild(leaf2);  root->addChild(composite1);  root->addChild(composite2);  root->operation(); 
}

五、python组合模式

以下是在python中实现组合模式:

class Component:  def operation(self):  pass  class Leaf(Component):  def __init__(self, value):  self.value = value  def operation(self):  print(f"Leaf operation: {self.value}")  class Composite(Component):  def __init__(self):  self.children = []  def add_child(self, child):  self.children.append(child)  def remove_child(self, child):  self.children = [c for c in self.children if c != child]  def operation(self):  for child in self.children:  child.operation()  def main():  root = Composite()  leaf1 = Leaf(1)  leaf2 = Leaf(2)  composite1 = Composite()  composite2 = Composite()  root.add_child(leaf1)  root.add_child(leaf2)  composite1.add_child(leaf1)  composite2.add_child(leaf2)  root.add_child(composite1)  root.add_child(composite2)  root.operation()  if __name__ == "__main__":  main()

 在这个示例代码中,定义了一个Component类作为抽象组件类,它有一个operation()方法,用于实现组件的操作。Leaf类和Composite类继承自Component类,分别表示叶节点和复合节点。Leaf类有一个value属性,表示节点的值,而Composite类有一个children属性,用于存储子节点。Composite类还实现了add_child()和remove_child()方法,用于添加和删除子节点。最后,在main()函数中创建了一个对象树,并调用operation()方法来执行操作。    

六、go组合模式

以下是一个示例,展示了如何在go中实现组合模式:

package main  import "fmt"  type Component interface {  Operation()  
}  type Leaf struct {  value int  
}  func (l *Leaf) Operation() {  fmt.Printf("Leaf operation: %d\n", l.value)  
}  type Composite struct {  children []*Component  
}  func (c *Composite) Operation() {  for _, child := range c.children {  child.Operation()  }  
}  func main() {  root := &Composite{}  leaf1 := &Leaf{value: 1}  leaf2 := &Leaf{value: 2}  composite1 := &Composite{}  composite2 := &Composite{}  root.children = []*Component{leaf1, leaf2, composite1, composite2}  composite1.children = []*Component{leaf1}  composite2.children = []*Component{leaf2}  root.Operation() 
}

在这个示例代码中,定义了一个Component接口,它有一个Operation()方法。Leaf和Composite结构体实现了Component接口。Leaf结构体有一个value属性,表示节点的值,而Composite结构体有一个children属性,用于存储子节点。Composite结构体还实现了Operation()方法,用于递归地调用子节点的Operation()方法。在main()函数中创建了一个对象树,并调用Operation()方法来执行操作。

七、PHP组合模式

以下是一个示例,展示了如何在PHP中实现组合模式:

<?php  class Component {  protected $name;  protected $children;  public function __construct($name) {  $this->name = $name;  $this->children = [];  }  public function addChild(Component $child) {  $this->children[] = $child;  }  public function removeChild(Component $child) {  $this->children = array_filter($this->children, function ($component) use ($child) {  return $component !== $child;  });  }  public function getName() {  return $this->name;  }  
}  class Leaf extends Component {  public function __construct($name) {  parent::__construct($name);  }  
}  class Composite extends Component {  public function __construct($name) {  parent::__construct($name);  }  public function getChildren() {  return $this->children;  }  
}  // 创建树形结构  
$root = new Composite("Root");  
$leaf1 = new Leaf("Leaf 1");  
$leaf2 = new Leaf("Leaf 2");  
$composite1 = new Composite("Composite 1");  
$composite2 = new Composite("Composite 2");  
$root->addChild($leaf1);  
$root->addChild($leaf2);  
$composite1->addChild($leaf1);  
$composite2->addChild($leaf2);  
$root->addChild($composite1);  
$root->addChild($composite2);  // 遍历树形结构并输出节点名称  
function traverse(Component $node) {  echo $node->getName() . " ";  if ($node instanceof Composite) {  foreach ($node->getChildren() as $child) {  traverse($child);  }  }  
}  
traverse($root); 

在这个示例中,Component类是抽象的根类,表示树中的节点。Leaf类表示叶节点,没有子节点;Composite类表示复合节点,可以包含子节点。通过addChild()和removeChild()方法,可以向复合节点添加或移除子节点。通过getChildren()方法,可以获取复合节点的子节点列表。最后,使用traverse()函数来遍历树形结构并输出节点名称。


《完结》

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

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

相关文章

Flyway Desktop updated

Flyway Desktop updated 为比较工件序列化和反序列化添加了额外的调试日志记录。 Flyway Desktop现在将记住以前用于创建项目和匹配克隆的位置。 新的脱机许可工作流现在已在Microsoft Windows上启用。 现在&#xff0c;在配置目标数据库列表时&#xff0c;环境ID是可见的。 现…

【虹科干货】Redis Enterprise vs ElastiCache——如何选择缓存解决方案?

使用Redis 或 Amazon ElastiCache 来作为缓存加速已经是业界主流的解决方案&#xff0c;二者各有什么优势&#xff1f;又有哪些区别呢&#xff1f; 文况速览&#xff1a; - Redis 是什么&#xff1f; - Redis Enterprise 是什么&#xff1f; - Amazon ElastiCache 是什么&…

tomcat动静分离

1.七层代理动静分离 nginx代理服务器&#xff1a;192.168.233.61 代理又是静态 tomcat1:192.168.233.71 tomcat2:192.168.233.72 全部关闭防火墙 在http模块里面 tomcat1&#xff0c;2 删除上面的hostname 148 配置 直接访问 http://192.168.66.17/index.jsp 2.四层七层动…

常见面试题-Redis专栏(二)

theme: cyanosis typora-copy-images-to: imgsRedisson 分布式锁&#xff1f;在项目中哪里使用&#xff1f;多久会进行释放&#xff1f;如何加强一个分布式锁&#xff1f; 答&#xff1a; 首先入门级别的分布式锁是通过 setnx 进行实现&#xff0c;使用 setnx 实现有四个注意…

中文编程开发语言工具应用案例:ps5体验馆计时收费管理系统软件

中文编程开发语言工具应用案例&#xff1a;ps5体验馆计时收费管理系统软件 软件部分功能&#xff1a; 1、计时计费功能&#xff1a;只需点开始计时即可&#xff0c;时间直观显示 2、商品管理功能&#xff1a;可以管理饮料等商品 3、会员管理功能&#xff1a;支持只用手机号作…

Arcgis 数据操作

在进行数据操作的时候&#xff0c;需要注意坐标系要一致&#xff0c;这是前提。 数据类型 文件地理数据库&#xff1a;gbd 个人地理数据库&#xff1a;mdb &#xff08;Mircosoft Access&#xff09; 矢量数据&#xff1a;shp 推荐使用gbd数据&#xff0c;效率会更高。 采…

【912.排序数组】

目录 一、题目描述二、算法原理2.1快速排序2.2归并排序 三、代码实现3.1快排代码实现3.2归并代码实现 一、题目描述 二、算法原理 2.1快速排序 2.2归并排序 三、代码实现 3.1快排代码实现 class Solution { public:int getRandom(int left,int right,vector<int>&…

[翻译]理解Postgres的IOPS:为什么数据即使都在内存,IOPS也非常重要

理解Postgres的IOPS&#xff1a;为什么数据即使都在内存&#xff0c;IOPS也非常重要 磁盘IOPS&#xff08;每秒输入/输出操作数&#xff09;是衡量磁盘系统性能的关键指标。代表每秒可以执行的读写操作数量。对于严重依赖于磁盘访问的PG来说&#xff0c;了解和优化磁盘IOPS对实…

Ubuntu系统下使用docker容器配置nginx并部署前端项目

1.下载 Nginx 镜像 命令 描述 docker pull nginx 下载最新版 Nginx 镜像 :2. 创建要挂载的宿主机目录 启动前需要先创建 Nginx 外部挂载的配置文件&#xff08; /home/nginx/conf/nginx.conf&#xff09; 之所以要先创建 , 是因为 Nginx 本身容器只存在 / etc/nginx 目录 ,…

iOS 13以下系统,使用iOS QQ 登录 SDK 崩溃问题

最近用iPhone 6p 系统&#xff1a;12.5.4 调用QQ三方登录&#xff0c;出现崩溃到初始化QQ SDK的位置 在询问了QQ官方客服后&#xff0c;得到了答复&#xff0c;可以放弃治疗了

2.IDEA的安装使用指南

学习Java的第二步应该是从IDEA下手&#xff0c;这篇博文介绍了它的安装及使用&#xff0c;希望大家看完后可以独立安装 ~ 文章目录 一、下载安装包二、安装 IDEA三、IDEA 初步上手 一、下载安装包 安装包可以从官网下载&#xff0c;也可以直接私信我拿取。这里主要介绍如何在官…

Swingbench 压力测试(超详细)

目录 前提需要有配置好的oracle哦 1、环境准备 2、安装Swingbench 3、造数据 4、压测 前提需要有配置好的oracle哦 1、环境准备 启动监听 lsnrctl start 启动数据库 sqlplus / as sysdba startup 创建表 CREATE TABLESPACE soe DATAFILE /u01/app/oracle/oradata/or…

2.卷积神经网络(CNN)

一句话引入&#xff1a; 如果我们要做图像识别&#xff0c;用的是一个200x200的图片&#xff0c;那么BP神经网络的输入层就需要40000个神经元&#xff0c;因为是全连接&#xff0c;所以整个BP神经网络的参数量就是160亿个&#xff0c;显然不能这样来训练网络&#xff0c;所以我…

【java】【重构一】分模块开发设计实战

目录 一、创建项目 1、先创建一个空项目 2、设置项目SDK等 二、创建父模块 选择springboot 1、创建父模块parent 2、删除多余文件&#xff0c;只保留pom.xml 3、修改pom.xml 4、将部分公共依赖加入到pom 三、创建实体类子模块entity 1、创建实体类子模块entity 2、…

Jprofiler V14中文使用文档

JProfiler介绍 什么是JProfiler? JProfiler是一个用于分析运行JVM内部情况的专业工具。 在开发中你可以使用它,用于质量保证,也可以解决你的生产系统遇到的问题。 JProfiler处理四个主要问题: 方法调用 这通常被称为"CPU分析"。方法调用可以通过不同的方式进行测…

C++中的继承(超详细)

C中的继承 1.继承的概念及定义1.1继承的概念1.2 继承定义1.2.1 定义格式1.2.2继承关系和访问限定符1.2.3继承基类成员访问方式的变化 2.基类和派生类对象赋值转换3.继承中的作用域4.派生类的默认成员函数5.继承与友元6.继承与静态成员7.继承的总结和反思 1.继承的概念及定义 1…

新兴网络安全威胁:数字防御新格局

根据Check Point Research (CPR)的数据&#xff0c;今年上半年犯罪活动大幅增加&#xff0c;第二季度全球每周网络攻击激增 8%&#xff0c;这创下了两年来的最高成交量。 勒索软件和黑客行为等传统威胁已经演变&#xff0c;犯罪团伙不断调整其方法和工具来渗透和影响世界各地的…

c语言练习93:环形链表的约瑟夫问题

环形链表的约瑟夫问题 环形链表的约瑟夫问题_牛客题霸_牛客网 描述 编号为 1 到 n 的 n 个人围成一圈。从编号为 1 的人开始报数&#xff0c;报到 m 的人离开。 下一个人继续从 1 开始报数。 n-1 轮结束以后&#xff0c;只剩下一个人&#xff0c;问最后留下的这个人编号是…

粘包和半包问题及解决办法

粘包问题是指数据在传输时&#xff0c;在一条消息中读取到了另一条消息的部分数据&#xff0c;这种现象就叫做粘包。 半包问题是指数据在传输时&#xff0c;接收端只收到了部分数据&#xff0c;而非完整的数据&#xff0c;就叫做半包。 产生粘包和半包问题原因&#xff1a; …

Error: GlobalConfigUtils setMetaData Fail Cause:java.lang.NullPointerException

文章目录 1、在开发中会出现这样的错误。2、其次&#xff0c;再看其他错误&#xff1a; 1、在开发中会出现这样的错误。 完整错误&#xff1a;Caused by: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Error: GlobalConfigUtils setMetaData Fail ! Cause…