设计模式之组合模式

设计模式之组合模式(Composite Pattern),又称为"整体---部分"(Part-Whole)模式,是一种结构型设计模式。它通过将一组相似的对象组合成树形结构来表示"部分-整体"的层次关系,使得用户对单个对象和组合对象的使用具有一致性。以下是对组合模式的详细介绍:

一、定义与特点

  • 定义:组合模式将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
  • 特点
    • 提供了表示对象集合的抽象数据类型。
    • 组合具有表示单个对象和组合对象的类层次结构。
    • 组合对象可以包含并可以统一处理其组合成分。

二、主要角色与类结构

组合模式通常包含以下几个主要角色:

  1. 抽象构件(Component)
    • 定义了一个对象的接口,用于访问和管理组件的子对象。
    • 可以是接口或抽象类,声明了对象共有的方法,包括用于访问和管理子构件的方法(如增加子构件、删除子构件、获取子构件等)。
    • 在透明式组合模式中,还声明了所有子类中的全部方法。
  2. 叶子构件(Leaf)
    • 在组合中表示叶子节点对象,是组合中的叶节点对象,没有子节点。
    • 实现了抽象构件中定义的行为,但对于那些访问及管理子构件的方法,可以通过异常等方式进行处理。
  3. 容器构件(Composite)/树枝构件(Composite)
    • 在组合中表示容器节点对象,是组合中的分支节点对象,包含子节点。
    • 其子节点可以是叶子节点,也可以是容器节点。
    • 提供一个集合用于存储子节点,并实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法。

三、实现方式

组合模式的实现根据所实现接口的区别分为两种形式,分别称为安全式组合模式透明式组合模式

  1. 安全式组合模式
    • 管理聚集的方法只出现在树枝构件类中,而不出现在树叶构件类中。
    • 抽象构件不定义出管理子对象的方法,这一定义由树枝构件对象给出。
    • 缺点是不够透明,因为树叶类和树枝类将具有不同的接口。
  2. 透明式组合模式
    • 要求所有的具体构件类,不论树枝构件还是树叶构件,均符合一个固定接口。
    • 客户端可以一致地处理所有的对象,无须区分是叶子节点还是容器节点。
    • 缺点是树叶构件本来没有管理子对象的方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。

四、优点

  1. 简化客户端代码:客户端可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象还是组合对象。
  2. 高扩展性:更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足"开闭原则"。

五、缺点

  1. 设计较复杂:客户端需要花更多时间理清类之间的层次关系。
  2. 安全性问题:透明式组合模式中,树叶构件需要实现一些不必要的方法,可能带来安全性问题。
  3. 性能问题:由于组合模式中的对象可能被存储在多个地方,可能导致性能问题,特别是在树形结构复杂的情况下。

六、适用场景

组合模式适用于需要表示对象的部分-整体层次结构的场景,如:

  • 文件系统中的文件和文件夹。
  • 窗体程序中的简单控件与容器控件。
  • 图形界面中的菜单项、按钮和其他控件的树形结构。
  • 表示公司或组织的部门结构。
  • XML文档的层次结构解析等。

七、示例

在文件系统的例子中,文件和文件夹可以被看作是一个整体-部分的关系。使用组合模式,可以创建一个统一的接口来处理文件和文件夹,无论是对文件进行操作还是对文件夹及其子文件夹进行操作,都可以使用相同的代码逻辑。

java 复制代码
// 抽象组件类  
abstract class FileSystemComponent {  
    private String name;  
  
    public FileSystemComponent(String name) {  
        this.name = name;  
    }  
  
    // 添加子组件的方法,默认为空实现(透明式组合模式)  
    public void add(FileSystemComponent component) {  
        throw new UnsupportedOperationException("This is a leaf.");  
    }  
  
    // 删除子组件的方法,默认为空实现  
    public void remove(FileSystemComponent component) {  
        throw new UnsupportedOperationException("This is a leaf.");  
    }  
  
    // 显示组件信息的方法  
    public void display(int depth) {  
        StringBuilder indent = new StringBuilder();  
        for (int i = 0; i < depth; i++) {  
            indent.append("--");  
        }  
        System.out.println(indent + name);  
    }  
  
    // 声明一个用于访问子组件的方法(可选,根据具体需求实现)  
    // ...  
  
    // 获取组件名称的方法  
    public String getName() {  
        return name;  
    }  
}  
  
// 叶子类(文件)  
class File extends FileSystemComponent {  
    public File(String name) {  
        super(name);  
    }  
  
    // 文件不需要添加或删除子组件,因此不需要重写这些方法  
}  
  
// 容器类(文件夹)  
class Folder extends FileSystemComponent {  
    private List<FileSystemComponent> children = new ArrayList<>();  
  
    public Folder(String name) {  
        super(name);  
    }  
  
    // 文件夹可以添加子组件  
    @Override  
    public void add(FileSystemComponent component) {  
        children.add(component);  
    }  
  
    // 文件夹可以删除子组件  
    @Override  
    public void remove(FileSystemComponent component) {  
        children.remove(component);  
    }  
  
    // 文件夹需要显示自己和所有子组件  
    @Override  
    public void display(int depth) {  
        super.display(depth);  
        for (FileSystemComponent child : children) {  
            child.display(depth + 1);  
        }  
    }  
}  
  
// 客户端代码  
public class CompositePatternDemo {  
    public static void main(String[] args) {  
        // 创建文件夹和文件  
        Folder root = new Folder("Root");  
        Folder folder1 = new Folder("Folder 1");  
        Folder folder2 = new Folder("Folder 2");  
        File file1 = new File("File 1.txt");  
        File file2 = new File("File 2.txt");  
  
        // 构建树结构  
        root.add(folder1);  
        root.add(folder2);  
        folder1.add(file1);  
        folder2.add(file2);  
  
        // 显示文件结构  
        root.display(0);  
    }  
}

在这个例子中,FileSystemComponent 是抽象组件类,它有一个 name 属性和一些基本方法(如 add, remove, display)。注意,addremove 方法在 FileSystemComponent 类中被声明为抛出 UnsupportedOperationException,因为叶子类(File)不应该包含这些方法。然而,在透明式组合模式中,我们更倾向于在叶子类中保留这些方法,并让它们空实现或抛出异常(如上所示),以保持接口的一致性。

File 类是叶子类,它继承自 FileSystemComponent 但不实现 addremove 方法,因为这些方法对于文件来说没有意义。

Folder 类是容器类,它继承自 FileSystemComponent 并重写了 addremove 方法以支持子组件的管理。同时,它还重写了 display 方法来递归地显示文件夹及其子组件。

最后,在 CompositePatternDemo 类的 main 方法中,我们创建了文件夹和文件对象,构建了树形结构,并调用了 display 方法来显示整个文件系统的结构。

八、结束语

组合模式是一种非常有用的设计模式,它提供了一种灵活的方式来处理对象之间的整体-部分关系,使得系统更加模块化和易于扩展。

如果对你有帮助,记得点赞收藏。

相关推荐
YGGP1 小时前
【结构型模式】代理模式
设计模式
庄小焱6 小时前
设计模式——中介者设计模式(行为型)
设计模式
庄小焱8 小时前
设计模式——备忘录设计模式(行为型)
设计模式
庄小焱8 小时前
设计模式——代理设计模式(结构型)
设计模式
哆啦A梦的口袋呀9 小时前
基于Python学习《Head First设计模式》第三章 装饰者模式
python·学习·设计模式
哆啦A梦的口袋呀9 小时前
基于Python学习《Head First设计模式》第五章 单件模式
python·学习·设计模式
季鸢10 小时前
Java设计模式之备忘录模式详解
java·设计模式·备忘录模式
摘星编程13 小时前
工厂方法模式深度解析:从原理到应用实战
java·设计模式·软件工程·工厂方法模式
何中应14 小时前
【设计模式-4.7】行为型——备忘录模式
java·设计模式·备忘录模式
suixinger_lmh1 天前
功能结构整理
unity·设计模式·c#·源代码管理