【设计模式深度剖析】【4】【结构型】【组合模式】| 以文件系统为例加深理解

【设计模式深度剖析】【4】【结构型】【组合模式】| 以文件系统为例加深理解

码农世界 2024-05-28 后端 69 次浏览 0个评论

👈️上一篇:适配器模式    |   下一篇:桥接模式👉️

设计模式-专栏👈️

目 录

  • 组合模式
  • 定义
    • 英文原话
    • 直译
    • 如何理解?
    • 3个角色
      • UML类图
      • 代码示例
      • 组合模式的优点
      • 组合模式的使用场景
      • 示例解析:文件系统

        组合模式

        组合模式(Composite Pattern)也叫合成模式,用来描述部分与整体的关系。

        • 高层模块调用简单。一棵树形结构中的所有节点都是 Component,局部和整体对调用者来说没有任何区别,即高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码。
        • 节点自由增加。使用组合模式后,如果想增加一个树枝节点、树叶节点只需要找到其父节点即可。

        当我们发现需求中是体现部分与整体层次的结构时,以及希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑用组合模式了。

        定义

        英文原话

        Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

        直译

        将对象组合成树形结构来表示“部分-整体”的层次结构。组合模式使得客户端能够统一地处理单个对象和对象的组合。

        如何理解?

        叶子构件和容器构件实现了抽象构件,即实现了相同的接口,用户对单个对象和组合对象的使用具有一致性。

        3个角色

        UML类图

        CompositePattern.png

        组合模式(Composite Pattern)允许我们将对象组合成树形结构以表示“部分整体”的层次结构,使得客户端以统一的方式处理单个对象和对象的组合。以下是组合模式中的主要角色:

        1. 抽象构件(Component):它可以是接口或抽象类,为叶子和容器对象声明接口,在该接口中包含用于管理子对象的方法以及用于自身操作的方法。在组合模式中,抽象构件定义了叶子和容器构件的共同行为。
        2. 叶子构件(Leaf):叶子对象继承自抽象构件,它没有子节点,通常用于实现抽象构件中的业务方法。在组合结构中,叶子节点没有子节点,其实现了在抽象构件中定义的行为。
        3. 容器构件(Composite):容器对象也继承自抽象构件,并包含一组子构件。它实现了在抽象构件中定义的行为,并提供了添加、删除和访问其子对象的方法。容器构件可以包含其他容器或叶子,从而实现复杂的树形结构。
        4. 客户端(Client):通过抽象构件接口与组合结构进行交互。对于客户端而言,叶子对象和容器对象是一致的,客户端不需要区分它们。

        代码示例

        以下是一个简单的Java示例来说明组合模式:

        // 抽象构件  
        public interface Component {
            void operation();
        }
        
        // 叶子构件  
        public class Leaf implements Component{
            @Override
            public void operation() {
                // 业务处理逻辑
                System.out.println("leaf...");
            }
        }
        
        // 容器构件  
        public class Composite implements Component {
            // 构件容器
            private ArrayList componentList = new ArrayList<>();
            // 添加构件
            public void add(Component component) {
                this.componentList.add(component);
            }
            // 删除构件
            public void remove(Component component) {
                this.componentList.remove(component);
            }
            // 获取子构件
            public ArrayList getChild() {
                return this.componentList;
            }
            @Override
            public void operation() {
                // 业务逻辑
                System.out.println("branch...");
            }
        }
        
        // 客户端代码  
        public class DemoTest {
            public static void main(String[] args) {
                // 创建一个根节点
                Composite root = new Composite();
                root.operation();
                // 创建树枝节点
                Composite branch = new Composite();
                // 创建叶子节点
                Leaf leaf = new Leaf();
                // 构建树形结构
                root.add(branch);
                branch.add(leaf);
                display(root);
            }
            // 遍历树(递归)
            public static void display(Composite root) {
                for (Component c : root.getChild()) {
                    if(c instanceof Leaf){// 如果节点类型是叶子节点
                        c.operation();
                    }else{// 树枝节点
                        c.operation();
                        display((Composite) c);
                    }
                }
            }
        }
        /* Output:
        branch...
        branch...
        leaf...
        *///~
        

        在这个例子中,我们有一个Component接口,它定义了一个名为operation的方法。Leaf类实现了这个接口,并提供了具体的实现。Composite类同样实现了Component接口,并维护了一个子组件的列表。

        组合模式的优点

        1. 高层模块调用简单。一棵树形机构中的所有节点都是 Component,局部和整体对调用者来说没有任何区别,即高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码。
        2. 节点自由增加。使用组合模式后,如果想增加一个树枝节点、树叶节点只需要找到其父节点即可。

        组合模式的使用场景

        使用组合模式的典型场景如下。

        1. 需要描述对象的部分和整体的等级结构,如树形菜单、文件和文件夹管理。
        2. 需要客户端忽略个体构件和组合构件的区别,平等对待所有的构件。

        示例解析:文件系统

        FileSystemDemo.png

        在生活中,一个常见的组合模式的例子是文件系统。文件系统中的文件和文件夹可以看作是组合模式的实现,其中文件夹可以包含文件和其他文件夹(子文件夹),而文件则不包含任何子项。

        以下是使用Java实现的示例,模拟了一个简单的文件系统:

        // 抽象构件:文件或文件夹  
        public interface FileSystemElement {  
            void display();  
        }  
        
        // 叶子构件:文件  
        public class File implements FileSystemElement {  
            private String name;  
          
            public File(String name) {  
                this.name = name;  
            }  
          
            @Override  
            public void display() {  
                System.out.println("File: " + name);  
            }  
        }  
        
        // 容器构件:文件夹  
        public class Folder implements FileSystemElement {  
            private String name;  
            private List children = new ArrayList<>();  
          
            public Folder(String name) {  
                this.name = name;  
            }  
          
            public void add(FileSystemElement element) {  
                children.add(element);  
            }  
          
            public void remove(FileSystemElement element) {  
                children.remove(element);  
            }  
          
            @Override  
            public void display() {  
                System.out.println("Folder: " + name);  
                for (FileSystemElement child : children) {  
                    child.display();  
                }  
            }  
        }  
        
        // 客户端代码
        public class DemoTest {
            public static void main(String[] args) {
                // 创建文件夹和文件  
                Folder rootFolder = new Folder("root");
                Folder documentsFolder = new Folder("Documents");
                Folder picturesFolder = new Folder("Pictures");
                File file1 = new File("example.txt");
                File file2 = new File("image.jpg");
                // 将文件和文件夹添加到对应的父文件夹中  
                rootFolder.add(documentsFolder);
                rootFolder.add(picturesFolder);
                documentsFolder.add(file1);
                picturesFolder.add(file2);
                // 显示整个文件系统的结构  
                rootFolder.display();
            }
        }
        /* Output:
        Folder: root
        Folder: Documents
        File: example.txt
        Folder: Pictures
        File: image.jpg
        *///~
        

        在这个示例中,FileSystemElement是抽象构件接口,它声明了一个display方法用于显示文件或文件夹的信息。File类实现了这个接口,表示一个具体的文件。Folder类也实现了这个接口,表示一个文件夹,并且它有一个children列表来存储其子元素(文件和文件夹)。Folder类还提供了添加和删除子元素的方法。

        在DemoTest类的main方法中,我们创建了一个根文件夹rootFolder,并添加了documentsFolder和picturesFolder两个子文件夹。接着,我们向这两个文件夹中分别添加了一个文件和图片。最后,我们调用rootFolder的display方法来显示整个文件系统的结构。

        这个输出展示了组合模式中的层次结构,其中文件夹可以包含文件和子文件夹,而文件则不包含任何子项。

        👈️上一篇:适配器模式    |   下一篇:桥接模式👉️

        设计模式-专栏👈️

转载请注明来自码农世界,本文标题:《【设计模式深度剖析】【4】【结构型】【组合模式】| 以文件系统为例加深理解》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,69人围观)参与讨论

还没有评论,来说两句吧...

Top