目 录CONTENT

文章目录

组合模式

半糖
2024-08-21 / 0 评论 / 0 点赞 / 17 阅读 / 8654 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2024-08-21,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

名称

组合模式(COMPOSITE)

目的

将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。

适用性

以下情况使用Composite模式:

• 想要表示对象的部分-整体层次结构。

• 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

结构

典型的Composite对象结构如下图所示

组件(Component)

  • 为组合中的对象声明接口。

  • 在适当的情况下,实现所有类共有接口的缺省(默认)行为。

  • 声明一个接口用于访问和管理Component的子组件。

  • (可选)在递归结构中定义一个接口,用于访问一个父部件,并在合适的情况下实现它。

叶子节点(Leaf)

  • 在组合中表示叶节点对象,叶节点没有子节点。

  • 在组合中定义图元对象的行为。

复合节点(Composite)

  • 定义有子部件的那些部件的行为。

  • 存储子部件。

  • 在Component接口中实现与子部件有关的操作。

客户端(Client):通过Component接口操纵组合部件的对象。

协作

用户使用Component类接口与组合结构中的对象进行交互。

如果接收者是一个叶节点,则直接处理请求。

如果接收者是Composite,它通常将请求发送给它的子部件,在转发请求之前与/或之后可能执行一些辅助操作。

效果

优点

  1. 定义了包含基本对象和组合对象的类层次结构。基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断的递归下去。客户代码中,任何用到基本对象的地方都可以使用组合对象。

  2. 简化客户代码。客户可以一致地使用组合结构和单个对象。通常用户不知道 (也不关心)处理的是一个叶节点还是一个组合组件。这就简化了客户代码 , 因为在定义组合的那些类中不需要写一些充斥着选择语句的函数。

  3. 使得更容易增加新类型的组件。新定义的Composite或Leaf子类自动地与已有的结构和客户代码一起工作,客户程序不需因新的Component类而改变。

  4. 符合设计原则:

    1. 符合单一职责原则,叶子组件和组合组件各司其职。

    2. 符合里氏替换原则,客户端可以用统一的接口处理单个对象或组合对象。

缺点

  1. 使设计变得更加一般化(通用)。容易增加新组件也会产生一些问题,那就是很难限制组合中的组件。有时希望一个组合只能有某些特定的组件。使用Composite时,不能依赖类型系统施加这些约束,而必须在运行时刻进行检查。

  2. 计复杂度增加。客户端需要花费更多时间理解类之间的层次关系。

  3. 不易用继承增加新功能。对于组合中的构件,使用继承的方式增加新功能可能会变得困难,因为这可能会破坏组合的结构

应用

问题

想要设计一个文件系统,系统中有文件夹和文件,为了方便我们抽象出组件File同时表示文件和文件夹,定义三种文件分别是图片、文本、视频,同时定义符合节点文件夹Folder。File中有名称和上级文件夹两个基本属性,同时定义了设置和访问父部件(Folder,这里用File也可以,只是因为父部件只会使文件夹不会是文件,所以用Folder)的方法,定义了访问和管理子部件的方法(display、remove、add,这里的方法参数必须是File,因为这些操作文件和文件夹都有可能),这样用户就可以使用File接口与组合结构中的对象进行交互。

UML

代码示例

组件:文件/文件夹

package com.ysj.part4.composite.component;

import com.ysj.part4.composite.composite.Folder;

public abstract class File {
    private Folder parentFolder;

    String name;

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

    public String getName() {
        return name;
    }

    public Folder getParentFolder() {
        return null != parentFolder ? parentFolder : new Folder("无父组件");
    }

    public void setParentFolder(Folder parentFolder) {
        this.parentFolder = parentFolder;
    }

    /**
     * 浏览文件夹内的文件和文件夹
     */
    public abstract void display();

    /**
     * 添加文件和文件夹
     *
     * @param file
     */
    public void add(File file) {
        System.out.println(name + "不支持添加文件和文件夹");
    }

    /**
     * 删除文件和文件夹
     *
     * @param file
     */
    public void remove(File file) {
        System.out.println(name + "不支持删除文件和文件夹");
    }
}

叶子节点:图片、文本、视频

package com.ysj.part4.composite.leaf;

import com.ysj.part4.composite.component.File;

public class ImagerFile extends File {

    public ImagerFile(String name) {
        super(name);
    }

    public void display() {
        System.out.println("这是图像文件,文件名:" + super.getName());
    }

}
package com.ysj.part4.composite.leaf;

import com.ysj.part4.composite.component.File;

public class TextFile extends File {

    public TextFile(String name) {
        super(name);
    }

    public void display() {
        System.out.println("这是文本文件,文件名:" + super.getName());
    }

}
package com.ysj.part4.composite.leaf;

import com.ysj.part4.composite.component.File;

public class VideoFile extends File {

    public VideoFile(String name) {
        super(name);
    }

    public void display() {
        System.out.println("这是影像文件,文件名:" + super.getName());
    }

}

复合节点:文件夹

package com.ysj.part4.composite.composite;

import com.ysj.part4.composite.component.File;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;

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

public class Folder extends File {
    private List<File> files;

    public Folder(String name){
        super(name);
        files = new ArrayList<File>();
    }

    public void display() {
        for(File file : files){
            if (!(file instanceof Folder)){
                file.display();
                continue;
            }
            System.out.println("这是一个文件夹,文件夹名:" + file.getName());
        }
    }

    public void add(File file){
        // 所添加的文件设置父文件夹为本文件夹
        file.setParentFolder(this);
        files.add(file);
    }

    public void remove(File file){
        files.remove(file);
    }

}

已知应用

DOM (Document Object Model)

DOM 是一种用于表示 HTML 和 XML 文档的标准对象模型。DOM 树本身就是一种典型的组合模式应用,其中节点可以是元素节点、文本节点或其他类型的节点,而这些节点又可以组成树形结构。

文件系统

许多操作系统中的文件系统也是基于组合模式实现的。文件夹可以包含其他文件夹或文件,形成了树状结构。

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区