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

news2024/12/23 16:41:59

简介:

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

在组合模式中,抽象根节点(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.coloradmin.cn/o/1119636.html

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

相关文章

数字图像处理实验记录五(图像的空间域增强-锐化处理)

前言&#xff1a; 文章目录 一、基础知识1&#xff0c;什么是锐化&#xff1f;2&#xff0c;为什么要锐化&#xff1f;3&#xff0c;怎么进行锐化&#xff1f; 二、实验要求任务1&#xff1a;任务2&#xff1a;任务3&#xff1a; 三、实验记录&#xff1a;任务1&#xff1a;任…

计算机网络第三章习题

1.假定1km长的CSMA/CD网络的数据率为1Gb/s。设信号在网络上的传播 速率为200000km/s。求能够使用此协议的最短帧长. 问题刨析: 逻辑链: 最短帧长数据传输率x争用期2τ(2倍端到端所需要的时间) 题目已经给出数据率为1Gb/s,所以我们要知道争用期2τ是多少. 端到端所需要的时间信…

订单 延后自动关闭,五种方案优雅搞定!

前 言 在开发中&#xff0c;往往会遇到一些关于延时任务的需求。例如 生成订单30分钟未支付&#xff0c;则自动取消生成订单60秒后,给用户发短信 对上述的任务&#xff0c;我们给一个专业的名字来形容&#xff0c;那就是延时任务 。那么这里就会产生一个问题&#xff0c;这个…

画程序流程图

一。在线程序流程图。类图和时序图 Integrations | Mermaid 二。VSCODE画UML图和各种种 1.下载plantuml.jarReleases plantuml/plantuml GitHubGenerate diagrams from textual description. Contribute to plantuml/plantuml development by creating an account on GitHu…

B-tree(PostgreSQL 14 Internals翻译版)

概览 B树(作为B树访问方法实现)是一种数据结构&#xff0c;它使您能够通过从树的根向下查找树的叶节点中所需的元素。为了明确地标识搜索路径&#xff0c;必须对所有树元素进行排序。B树是为有序数据类型设计的&#xff0c;这些数据类型的值可以进行比较和排序。 下面的机场代…

【在英伟达nvidia的jetson-orin-nx上使用调试摄像头-初步调试USB摄像头与Camera Conn.#0/#1接口-基础测试】

【在英伟达nvidia的jetson-orin-nx上使用调试摄像头-初步调试USB摄像头与Camera Conn.#0/#1接口-基础测试】 1、概述2、实验环境3、 物品说明&#xff08;0&#xff09;各种各样摄像头&#xff08;1&#xff09;USB摄像头&#xff08;2&#xff09;CSI摄像头&#xff08;3&…

【JavaEE】线程安全的集合类 -- 多线程篇(9)

线程安全的集合类 多线程环境使用 ArrayList多线程环境使用队列多线程环境使用哈希表 多线程环境使用 ArrayList 自己使用同步机制 (synchronized 或者 ReentrantLock)Collections.synchronizedList(new ArrayList); synchronizedList 是标准库提供的一个基于 synchronized 进…

【AIGC】百度文库文档助手之 - 一键生成PPT

百度文库文档助手之 - 一键生成PPT 引言一、文档助手&#xff1a;体验一键生成PPT二、文档助手&#xff1a;进阶用法三、其它生成PPT的方法3.1 ChatGPT3.2 文心一言 引言 就在上个月百度文库升级为一站式智能文档平台&#xff0c;开放四大AI能力&#xff1a;智能PPT、智能总结、…

正则表达式提取http和http内容

http.* 这样匹配到的就是我们要的内容 取反正则&#xff1a;^((?!要取反的正则表达式).)*$ 取反&#xff1a;^((?!http.).)$ 这样匹配到的就是我们不要的内容 提取域名 /[(http|ftp|https):\/\/]?([\w_-](?:(?:\.[\w_-])))([\w.,?^%&:\/~#-]*[\w?^%&\/~#-]…

APK与小程序渗透

文章目录 APK与小程序渗透1. APK2. 小程序2.1 源代码2.2 小程序的默认下载位置 3. 安装证书3.1 openssl配置环境变量3.2 安装证书 APK与小程序渗透 由于APK和小程序与服务器通信还是采用的是https协议&#xff0c;只是使用了加密。只要获取到了HTTP的请求报文就可以回归到Web渗…

单目3D目标检测论文汇总

基于语义和几何约束的方法 1. Deep3DBox 3D Bounding Box Estimation Using Deep Learning and Geometry [CVPR2017] https://arxiv.org/pdf/1612.00496.pdfhttps://zhuanlan.zhihu.com/p/414275118 核心思想&#xff1a;通过利用2D bounding box与3D bounding box之间的几何约…

『C语言进阶』字符函数和内存函数(2)

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f516;系列专栏&#xff1a; C语言、Linux、Cpolar ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 一、strtok函数1.1 函数认识1.2 注意事项 二、strerror函数2.1 函数认识2.2 注意事项 三、memcpy函数3.1 函数…

1024渗透测试如何暴力破解其他人主机的密码(第十一课)

1024渗透测试如何暴力破解其他人主机的密码(第十一课) 1 crunch 工具 crunch是一个密码生成器&#xff0c;一般用于在渗透测试中生成随机密码或者字典攻击。下面是常见的一些使用方法&#xff1a; 生成密码字典 生成6位数字的字典&#xff1a;crunch 6 6 -t -o dict.txt …

【LeetCode】145. 二叉树的后序遍历 [ 左子树 右子树 根结点]

题目链接 文章目录 Python3方法一&#xff1a; 递归 ⟮ O ( n ) ⟯ \lgroup O(n) \rgroup ⟮O(n)⟯方法二&#xff1a; 迭代 ⟮ O ( n ) ⟯ \lgroup O(n) \rgroup ⟮O(n)⟯方法三&#xff1a; Morris ⟮ O ( n ) 、 O ( 1 ) ⟯ \lgroup O(n)、O(1) \rgroup ⟮O(n)、O(1)⟯写…

学成在线第二天-查询课程、查询课程分类、新增课程接口实现以及跨域的处理思路和全局异常处理的使用以及面试题

目录 一、接口的实现 二、跨域的处理思路 三、全局异常处理 四、面试题 五、总结 一、接口的实现 1. 查询课程接口 思路&#xff1a; 典型的分页查询 按需查询 模糊查询的查询 controller&#xff1a; ApiOperation(value "课程列表", notes "课程…

字节码进阶之java Instrumentation原理详解

文章目录 0. 前言1. 基础2. Java Instrumentation API使用示例 3. Java Agent4. 字节码操作库5. 实际应用6. 注意事项和最佳实践 0. 前言 Java Instrumentation是Java API的一部分&#xff0c;它允许开发人员在运行时修改类的字节码。使用此功能&#xff0c;可以实现许多高级操…

记录一次线下渗透电气照明系统(分析与实战)

项目地址:https://github.com/MartinxMax/S-Clustr 注意 本次行动未造成任何设备损坏,并在道德允许范围内测试 >ethical hacking< 发现过程 在路途中,发现一个未锁的配电柜,身为一个电工自然免不了好奇心(非专业人士请勿模仿,操作不当的话220V人就直了) 根据照片,简…

c++踩坑点,类型转换

std::string转换到PVOID std::string转换到PVOID的方式如下 这样的话成功转换 “const char *” 类型的实参与 “WCHAR *” “const char *” 类型的实参与 “WCHAR *” 类型的形参不兼容 可以看到这种报错&#xff0c;可以直接强转如下&#xff1a; 但是在我们这里不适…

论文总结:EXPRESSIVE SPEECH-DRIVEN FACIAL ANIMATION WITH CONTROLLABLE EMOTIONS

存在的问题:现有的语音驱动面部动画方法可以产生令人满意的嘴部运动和嘴唇同步,但在情感表达和情感控制方面存在不足。 作者使用wav2vec2.0和transformer encoder来获取文本向量和全局风格向量。将其拼接起来通过Auido2FLAME模块来预测flame的参数,Auido2FLAME由多层CNN组成…

大厂秋招真题【贪心】大疆20230813秋招T1-矩形田地

题目描述与示例 题目描述 给定一个矩形田地&#xff0c;其高度为 h 且宽度为 w。同时&#xff0c;你将获得两个整数数组 horizontalCutting 和 verticalCutting&#xff0c;其中 horizontalCutting[i] 表示从矩形田地顶部到第 i 个水平切口的距离&#xff0c;verticalCutting…