【设计模式】组合模式

1.模式简述

想象一个场景,有很多的文件和文件夹,文件夹中还套着很多的子文件夹。你需要统计所有文件的总大小。但是由于这些文件分布在不同的文件夹中,你无法做到一个一个的点开去统计,你想用程序的方式实现,读取所有的文件夹,然后一层一层的查询。当你尝试统计了几个文件夹后你发现还是无法快速实现。这里就需要组合模式帮你解决这个问题。当你统计文件夹中文件的大小时,无需关心文件夹中是否嵌套了子文件夹。直接调用统一的方法。系统将自动递归的计算所有的文件的大小,这就是组合模式的核心:统一处理个体和组合对象。

适用场景

需要使用树结构标识的菜单或者组织架构。

客户端统一处理单个对象和组合对象。

优点

代码简洁,不需要区分对象类型。

新增组件类型容易,符合开闭原则。

缺点

设计过于抽象,会增加开发人员理解成本。

叶子节点需要实现不需要的方法,需要使用异常捕获。

2.示例代码

类图

代码

java 复制代码
// 组件抽象(可以是接口或抽象类)
interface FileSystemComponent {
void showDetails();
}


// 叶子节点:文件
class File implements FileSystemComponent {
private String name;


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


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


// 组合节点:文件夹
class Directory implements FileSystemComponent {
private String name;
private List<FileSystemComponent> children = new ArrayList<>();


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


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


@Override
public void showDetails() {
System.out.println("Directory: " + name);
for (FileSystemComponent child : children) {
child.showDetails(); // 递归调用子节点的方法
}
}
}


// 客户端调用
public class Client {
public static void main(String[] args) {
File file1 = new File("a.txt");
File file2 = new File("b.jpg");


Directory dir1 = new Directory("Documents");
dir1.add(file1);
dir1.add(file2);


Directory root = new Directory("C:");
root.add(dir1);
root.showDetails(); // 统一调用
}
}

3.实际案例

设计一个多级菜单系统,菜单可以包含子菜单或菜单项。

统一接口:所有对象(组合/叶子)实现同一接口。

递归操作:组合对象内部通过递归处理子节点。

透明性:客户端无需区分组合对象和叶子对象。

代码实现

java 复制代码
// 组件接口
interface MenuComponent {
    void display();
}


// 叶子节点:菜单项
class MenuItem implements MenuComponent {
    private String name;


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


    @Override
    public void display() {
        System.out.println("菜单项: " + name);
    }
}


// 组合节点:子菜单
class SubMenu implements MenuComponent {
    private String name;
    private List<MenuComponent> children = new ArrayList<>();


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


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


    @Override
    public void display() {
        System.out.println("子菜单: " + name);
        for (MenuComponent child : children) {
            child.display(); // 递归显示子菜单或菜单项
        }
    }
}


// 客户端使用
public class MenuClient {
    public static void main(String[] args) {
        MenuComponent mainMenu = new SubMenu("主菜单");


        MenuComponent fileMenu = new SubMenu("文件");
        fileMenu.add(new MenuItem("新建"));
        fileMenu.add(new MenuItem("打开"));


        MenuComponent editMenu = new SubMenu("编辑");
        editMenu.add(new MenuItem("复制"));
        editMenu.add(new MenuItem("粘贴"));


        mainMenu.add(fileMenu);
        mainMenu.add(editMenu);


        mainMenu.display(); // 统一调用显示方法
    }
}
相关推荐
周某某~21 分钟前
二.单例模式‌
java·单例模式·设计模式
十五年专注C++开发37 分钟前
设计模式之单例模式(二): 心得体会
开发语言·c++·单例模式·设计模式
hstar952739 分钟前
三十五、面向对象底层逻辑-Spring MVC中AbstractXlsxStreamingView的设计
java·后端·spring·设计模式·架构·mvc
pengyu1 小时前
【Java设计原则与模式之系统化精讲:壹】 | 编程世界的道与术(实战指导篇)
java·后端·设计模式
小吕学编程2 小时前
策略模式实战:Spring中动态选择商品处理策略的实现
java·开发语言·设计模式
pan_junbiao3 小时前
Spring框架的设计模式
java·spring·设计模式
蔡蓝16 小时前
设计模式-建造者模式
服务器·设计模式·建造者模式
不伤欣21 小时前
游戏设计模式 - 子类沙箱
游戏·unity·设计模式
漫谈网络21 小时前
MVC与MVP设计模式对比详解
设计模式·mvc
蔡蓝21 小时前
设计模式-观察着模式
java·开发语言·设计模式