设计模式——10. 组合模式

这篇具有很好参考价值的文章主要介绍了设计模式——10. 组合模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 说明

组合模式是一种结构型设计模式,用于将对象组合成树状结构以表示“部分-整体”的层次结构。它允许客户端以一致的方式处理单个对象和组合对象(包含多个对象的容器),使得客户端无需关心它们之间的差异。

组合模式通常涉及两种主要角色:

  1. 叶子节点(Leaf):这是组合中的基本对象,它不能包含其他对象。叶子节点执行特定操作。
  2. 组合节点(Composite):这是包含子对象的复杂对象。组合节点通常执行某种操作,然后将操作传递给其子节点。

组合模式的关键思想是将叶子节点和组合节点都视为相同类型的对象,它们都实现了相同的接口,从而客户端可以一致地处理它们。

组合模式的主要优点包括:

  1. 简化客户端代码:客户端不需要区分叶子节点和组合节点,可以统一处理。
  2. 支持嵌套结构:可以轻松创建包含多层次嵌套的树状结构。
  3. 提供了高扩展性:可以轻松地添加新的叶子节点或组合节点,而不会影响现有代码。

总之,组合模式允许你创建具有灵活结构的对象树,从而更容易地管理和操作对象的层次结构。

2. 使用的场景

组合模式通常适用于以下场景:

  1. 层次结构对象:当你需要表示对象的层次结构,其中对象可以是单个元素或包含其他对象的容器时,组合模式非常有用。例如,文件系统中的文件和文件夹,图形用户界面中的窗口和控件,组织结构中的部门和员工等。
  2. 统一处理:当你希望客户端代码能够统一处理单个对象和组合对象时,组合模式是一种有用的方式。客户端不需要关心它们处理的是叶子节点还是组合节点。
  3. 递归结构:当对象之间存在递归关系,且你希望以一种统一的方式遍历和操作整个结构时,组合模式非常适合。例如,在解析树、XML文档、目录结构等场景中。
  4. 添加新组件类型:当你需要在不修改现有代码的情况下添加新的组件类型时,组合模式是一种非常灵活的设计。你只需要创建新的叶子节点或组合节点,并确保它们实现了相同的接口。
  5. 操作整体和部分:当你需要对整体和部分进行一致性操作时,组合模式非常有用。例如,对于图形界面中的窗口和其中的所有控件,你可以同时执行操作,而不需要单独处理每个控件。

总之,组合模式适用于那些具有层次结构、需要统一处理、具有递归关系或需要支持动态添加新组件类型的情况。它有助于简化复杂结构的管理和操作,提高代码的可维护性和扩展性。

3. 应用例子

以下是一个使用 Python 实现的组合模式示例,模拟了文件系统的层次结构:

from abc import ABC, abstractmethod

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

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

    def display(self):
        print(f"File: {self.name}")

# 组合节点类 - 文件夹
class Folder(FileSystemComponent):
    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 display(self):
        print(f"Folder: {self.name}")
        for child in self.children:
            child.display()

# 客户端代码
if __name__ == "__main__":
    root = Folder("Root")
    file1 = File("File 1")
    file2 = File("File 2")
    folder1 = Folder("Folder 1")
    file3 = File("File 3")

    root.add(file1)
    root.add(file2)
    root.add(folder1)
    folder1.add(file3)

    root.display()

在这个示例中,我们有两种类型的节点:File 表示叶子节点(文件),Folder 表示组合节点(文件夹)。它们都实现了 FileSystemComponent 抽象类,其中包括 display 方法以显示节点的信息。

客户端代码创建了一个包含文件和文件夹的层次结构,并使用 display 方法遍历并显示整个文件系统结构。这个示例演示了组合模式的核心概念,即叶子节点和组合节点具有相同的接口,并且客户端可以一致地处理它们。

4. 实现要素

组合模式的主要要素包括以下部分:

  1. Component(组件):这是一个抽象类或接口,定义了叶子节点和组合节点的公共接口。它通常包括了一些操作,例如操作叶子节点或组合节点的方法。
  2. Leaf(叶子节点):这是组合中的基本对象,它实现了 Component 接口。叶子节点不能包含其他对象,通常执行具体的操作。
  3. Composite(组合节点):这是包含子对象的复杂对象,也实现了 Component 接口。组合节点执行某些操作,然后将操作传递给其子节点。组合节点可以包含叶子节点或其他组合节点,从而创建层次结构。

5. UML图

下面是组合模式的简化 UML 类图:

         +-------------------------+
         |        Component        |
         +-------------------------+
         | + operation()           |
         +-------------------------+
                 /       \
                /         \
               /           \
              /             \
 +----------------+   +----------------+
 |     Leaf       |   |    Composite   |
 +----------------+   +----------------+
 |                |   |                |
 +----------------+   +----------------+

在这个 UML 类图中,Component 定义了操作,Leaf 和 Composite 都实现了 Component 接口。Leaf 表示叶子节点,Composite 表示组合节点。
组合模式的关键思想是使叶子节点和组合节点具有相同的接口,以便客户端可以一致地处理它们。这种统一性使得组合模式能够处理具有层次结构的对象,而不需要客户端关心对象的类型。

6. Java/golang/javascrip/C++ 等语言实现方式

6.1 Java实现

上述例子用Java语言实现示例如下:

import java.util.ArrayList;
import java.util.List;

// 抽象组件类
abstract class FileSystemComponent {
    abstract void display();
}

// 叶子节点类 - 文件
class File extends FileSystemComponent {
    private String name;

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

    @Override
    void display() {
        System.out.println("File: " + name);
    }
}

// 组合节点类 - 文件夹
class Folder extends FileSystemComponent {
    private String name;
    private List<FileSystemComponent> children = new ArrayList<>();

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

    public void add(FileSystemComponent component) {
        children.add(component);
    }

    public void remove(FileSystemComponent component) {
        children.remove(component);
    }

    @Override
    void display() {
        System.out.println("Folder: " + name);
        for (FileSystemComponent child : children) {
            child.display();
        }
    }
}

// 客户端代码
public class Main {
    public static void main(String[] args) {
        Folder root = new Folder("Root");
        File file1 = new File("File 1");
        File file2 = new File("File 2");
        Folder folder1 = new Folder("Folder 1");
        File file3 = new File("File 3");

        root.add(file1);
        root.add(file2);
        root.add(folder1);
        folder1.add(file3);

        root.display();
    }
}

6.2 Golang实现

上述例子用golang实现示例如下:

package main

import "fmt"

// 抽象组件接口
type FileSystemComponent interface {
    Display()
}

// 叶子节点类 - 文件
type File struct {
    name string
}

func NewFile(name string) *File {
    return &File{name}
}

func (f *File) Display() {
    fmt.Printf("File: %s\n", f.name)
}

// 组合节点类 - 文件夹
type Folder struct {
    name     string
    children []FileSystemComponent
}

func NewFolder(name string) *Folder {
    return &Folder{name, make([]FileSystemComponent, 0)}
}

func (d *Folder) Add(component FileSystemComponent) {
    d.children = append(d.children, component)
}

func (d *Folder) Remove(component FileSystemComponent) {
    for i, c := range d.children {
        if c == component {
            d.children = append(d.children[:i], d.children[i+1:]...)
            return
        }
    }
}

func (d *Folder) Display() {
    fmt.Printf("Folder: %s\n", d.name)
    for _, c := range d.children {
        c.Display()
    }
}

func main() {
    root := NewFolder("Root")
    file1 := NewFile("File 1")
    file2 := NewFile("File 2")
    folder1 := NewFolder("Folder 1")
    file3 := NewFile("File 3")

    root.Add(file1)
    root.Add(file2)
    root.Add(folder1)
    folder1.Add(file3)

    root.Display()
}

6.3 Javascript实现

上述例子用javascript实现示例如下:

// 抽象组件类
class FileSystemComponent {
    display() {}
}

// 叶子节点类 - 文件
class File extends FileSystemComponent {
    constructor(name) {
        super();
        this.name = name;
    }

    display() {
        console.log(`File: ${this.name}`);
    }
}

// 组合节点类 - 文件夹
class Folder extends FileSystemComponent {
    constructor(name) {
        super();
        this.name = name;
        this.children = [];
    }

    add(component) {
        this.children.push(component);
    }

    remove(component) {
        this.children = this.children.filter(child => child !== component);
    }

    display() {
        console.log(`Folder: ${this.name}`);
        for (const child of this.children) {
            child.display();
        }
    }
}

// 客户端代码
const root = new Folder("Root");
const file1 = new File("File 1");
const file2 = new File("File 2");
const folder1 = new Folder("Folder 1");
const file3 = new File("File 3");

root.add(file1);
root.add(file2);
root.add(folder1);
folder1.add(file3);

root.display();

6.4 C++实现

上述例子用C++实现如下:

#include <iostream>
#include <vector>

// 抽象组件类
class FileSystemComponent {
public:
    virtual void display() = 0;
};

// 叶子节点类 - 文件
class File : public FileSystemComponent {
private:
    std::string name;

public:
    File(const std::string& name) : name(name) {}

    void display() override {
        std::cout << "File: " << name << std::endl;
    }
};

// 组合节点类 - 文件夹
class Folder : public FileSystemComponent {
private:
    std::string name;
    std::vector<FileSystemComponent*> children;

public:
    Folder(const std::string& name) : name(name) {}

    void add(FileSystemComponent* component) {
        children.push_back(component);
    }

    void remove(FileSystemComponent* component) {
        for (auto it = children.begin(); it != children.end(); ++it) {
            if (*it == component) {
                children.erase(it);
                break;
            }
        }
    }

    void display() override {
        std::cout << "Folder: " << name << std::endl;
        for (auto child : children) {
            child->display();
        }
    }
};

int main() {
    Folder root("Root");
    File file1("File 1");
    File file2("File 2");
    Folder folder1("Folder 1");
    File file3("File 3");

    root.add(&file1);
    root.add(&file2);
    root.add(&folder1);
    folder1.add(&file3);

    root.display();

    return 0;
}

7. 练习题

在一个文件系统中,有文件和文件夹两种类型的元素。文件是叶子节点,而文件夹是组合节点。使用组合模式来建模这个文件系统。

要求:

  1. 创建一个抽象组件类 FileSystemComponent,其中包括一个抽象方法 display()。
  2. 创建一个叶子节点类 File,它继承自 FileSystemComponent,包括一个属性 name 表示文件名,并实现 display() 方法以显示文件名。
  3. 创建一个组合节点类 Folder,它继承自 FileSystemComponent,包括一个属性 name 表示文件夹名,以及一个保存子元素的容器,实现 add() 和 remove() 方法来添加和移除子元素,并实现 display() 方法以显示文件夹名以及其中的子元素。
  4. 在客户端代码中创建一个文件系统层次结构,包括文件和文件夹,然后使用 display() 方法显示整个文件系统结构。

你可以使用 C++、Java、Python 或任何其他编程语言来实现这个练习。
你可以在评论区里或者私信我回复您的答案,这样我或者大家都能帮你解答,期待着你的回复~文章来源地址https://www.toymoban.com/news/detail-728663.html

到了这里,关于设计模式——10. 组合模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java23种设计模式-结构型模式之组合模式

    组合模式 (Composite Pattern):将 对象组合成树状结构 以表示“ 部分-整体 ”层次结构,同时保持对单个对象和组合对象的一致性操作,主要目的是简化客户端代码,因为它可以统一处理单个对象和组合对象。 通常包含以下几个角色: 角色1. 抽象组件 (Component):声明了 组

    2024年04月26日
    浏览(41)
  • 【Design Pattern 23种经典设计模式源码大全】C/Java/Go/JS/Python/TS等不同语言实现

    经典设计模式源码详解,用不同语言来实现,包括Java/JS/Python/TypeScript/Go等。结合实际场景,充分注释说明,每一行代码都经过检验,确保可靠。 设计模式是一个程序员进阶高级的必然选择,不懂设计模式,就像写文章不懂得层次,盖房子没有结构。只有充分懂得设计之道,

    2023年04月11日
    浏览(43)
  • Java设计模式之结构型-组合模式(UML类图+案例分析)

    目录 一、基础概念 二、UML类图 三、角色设计 四、案例分析 4.1、基本实现 4.2、菜单遍历  五、总结  组合模式(Composite Pattern)又叫部分-整体模式,它通过将对象组合成树形结构来表示“整体-部分”的层次关系,允许用户统一单个对象和组合对象的处理逻辑。 角色 描述

    2024年02月16日
    浏览(50)
  • 【设计模式——学习笔记】23种设计模式——组合模式Composite(原理讲解+应用场景介绍+案例介绍+Java代码实现)

    编写程序展示一个学校院系结构: 需求是这样,要在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系 【传统方式】 将学院看做是学校的子类,系是学院的子类,小的组织继承大的组织 分析: 在一个页面中展示出学校的院系组成,一个学校有多个

    2024年02月15日
    浏览(45)
  • 【Java面试题】设计模式之七种结构性模式——代理模式、适配器模式、桥接模式、装饰模式、外观模式、享元模式、组合模式

    目录 一、代理模式 二、适配器模式 三、桥接模式 四、装饰模式 五、外观模式 六、享元模式 七、组合模式 概念: 代理模式是为其他对象提供一种以代理控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对

    2023年04月09日
    浏览(52)
  • Python入门【​编辑、组合、设计模式_工厂模式实现 、设计模式_单例模式实现、工厂和单例模式结合、异常是什么?异常的解决思路 】(十七)

    👏作者简介:大家好,我是爱敲代码的小王,CSDN博客博主,Python小白 📕系列专栏:python入门到实战、Python爬虫开发、Python办公自动化、Python数据分析、Python前后端开发 📧如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀 🔥如果感觉博主的文章还不错的

    2024年02月14日
    浏览(44)
  • 10.python设计模式【代理模式】

    内容:为其他对象提供一种代理一控制对这个对象的访问 应用场景: 远程代理: 为远程的对象提供代理 虚代理:根据需要创建很大的对象 保护代理:控制对原始对象的访问,用于对象有不同访问权限时 UML图 举个例子: 需求:完成一个文件读取和写入,完成远程代理、需

    2024年02月15日
    浏览(74)
  • 设计模式——组合模式

    组合模式(Composite Pattern):组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。 组合模式将

    2024年02月11日
    浏览(68)
  • 设计模式-组合模式

    组合模式可以使用一棵树来表示 组合模式使得用户可以使用一致的方法操作单个对象和组合对象 组合模式又叫部分整体模式,将对象组合成树形结构以表示“部分-整体”的层次结构,可以更好的实现管理操作,部分-整体对象的操作基本一样,但是应该还会有不一样的地方

    2024年02月10日
    浏览(50)
  • 设计模式——组合模式08

    组合模式:把类似对象或方法组合成结构为树状的设计思路。 例如部门之间的关系。 设计模式,一定要敲代码理解 满足开闭原则。叶子结点与非叶子结点都继承或实现同一抽象,只是叶子功能权限少,而非叶子结点需要容器记录子节点。 代码下载

    2024年04月11日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包