• 设计模式-组合模式(Composite)


    一、组合模式概述

    1.1 什么是组合模式

    组合模式(Composite Pattern),也被称为部分-整体模式、合成模式或对象树,是一种结构型设计模式。这种模式将一组具有相似功能的对象视为一个单一的对象,使得客户可以以统一的方式处理单个对象和组合对象。

    该模式依据树形结构来组合对象,用来表示部分以及整体层次。在特定的应用场景下,如需要表示的功能的结构可以被抽象成树状结构时,就非常适合使用组合模式。例如,在一个模拟的公司架构中,公司被视为一个整体,它下面可以设有行政部门和IT部门,而这些部门又可以有自己的下属部门。

    总的来说,组合模式提供了一种方式来展示和操作层次性的结构化对象,增强了代码的灵活性和可维护性。

    1.2 简单实现组合模式

    实现组合模式的步骤如下:

    • 1、定义一个抽象组件类,包含一个指向其子组件的引用。
    • 2、创建具体组件类,这些类实现了抽象组件类中定义的方法。
    • 3、创建一个组合组件类,该类也实现了抽象组件类中定义的方法。在组合组件类中,维护一个子组件列表,并实现添加、删除和遍历子组件的方法。
    • 4、在客户端代码中,使用组合组件类来构建层次结构的对象,并通过调用抽象组件类中定义的方法来操作对象。

    以下是一个简单的Java示例代码:

    // 抽象组件类
    abstract class Component {
        protected String name;
    
        public Component(String name) {
            this.name = name;
        }
    
        public abstract void operation();
    }
    
    // 具体组件类A
    class ConcreteComponentA extends Component {
        public ConcreteComponentA(String name) {
            super(name);
        }
    
        @Override
        public void operation() {
            System.out.println("ConcreteComponentA: " + name);
        }
    }
    
    // 具体组件类B
    class ConcreteComponentB extends Component {
        public ConcreteComponentB(String name) {
            super(name);
        }
    
        @Override
        public void operation() {
            System.out.println("ConcreteComponentB: " + name);
        }
    }
    
    // 组合组件类
    class CompositeComponent extends Component {
        private List<Component> children = new ArrayList<>();
    
        public CompositeComponent(String name) {
            super(name);
        }
    
        public void add(Component component) {
            children.add(component);
        }
    
        public void remove(Component component) {
            children.remove(component);
        }
    
        @Override
        public void operation() {
            System.out.println("CompositeComponent: " + name);
            for (Component child : children) {
                child.operation();
            }
        }
    }
    
    // 客户端代码
    public class Main {
        public static void main(String[] args) {
            CompositeComponent root = new CompositeComponent("Root");
            CompositeComponent child1 = new CompositeComponent("Child1");
            CompositeComponent child2 = new CompositeComponent("Child2");
    
            root.add(child1);
            root.add(child2);
    
            ConcreteComponentA a1 = new ConcreteComponentA("A1");
            ConcreteComponentB b1 = new ConcreteComponentB("B1");
            ConcreteComponentA a2 = new ConcreteComponentA("A2");
            ConcreteComponentB b2 = new ConcreteComponentB("B2");
    
            child1.add(a1);
            child1.add(b1);
            child2.add(a2);
            child2.add(b2);
    
            root.operation();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    在这个示例中,我们创建了一个组合组件CompositeComponent,它包含了两个子组件child1和child2。然后,我们在客户端代码中向这些子组件中添加了具体的组件ConcreteComponentA和ConcreteComponentB。最后,我们调用root.operation()方法,输出组合组件及其子组件的操作结果。

    1.3 使用组合模式的注意事项

    • 1、组合模式适用于具有层次结构的对象,如果对象之间没有明显的层次关系,则不适合使用组合模式。
    • 2、抽象组件类应该定义一些通用的方法,如添加、删除和遍历子组件等方法,这些方法可以在具体组件类中进行重写。
    • 3、组合组件类中的子组件列表可以使用数组或链表实现,但需要考虑性能问题。如果需要频繁地添加和删除子组件,建议使用链表;如果子组件数量较少且不需要频繁操作,可以使用数组。
    • 4、在客户端代码中,可以通过组合组件类来构建复杂的对象结构,并通过调用抽象组件类中定义的方法来操作对象。
    • 5、组合模式可以简化客户端代码的编写和维护,但如果滥用组合模式,可能会导致系统变得复杂和难以维护。因此,在使用组合模式时需要权衡利弊,避免过度设计。

    二、组合模式的用途

    • 1、定义层次结构:组合模式可以清晰地定义分层次的复杂对象,表示对象的全部或部分层次。
    • 2、忽略层次差异:通过使用组合模式,客户端代码可以忽略层次之间的差异,从而方便对整个层次结构进行控制。
    • 3、简化客户端代码:组合模式使得客户端代码可以一致地处理单个对象和组合对象,无需关心自己处理的是单个对象,还是组合对象,这大大简化了客户端代码。
    • 4、符合开闭原则:组合模式允许在运行时添加新的元素,而无需更改源代码,这满足了“开闭原则”。
    • 5、使设计变得更加抽象:通过使用组合模式,设计变得更加抽象,更具有一般性。

    然而,值得注意的是,使用组合模式时也需要注意一些限制,例如当限制类型时,可能比较复杂;例如某个目录中只能包含文本文件,使用组合模式时,不能依赖类型系统施加约束,这些都必须来自于节点的抽象层,在这种情况下,必须通过在运行时进行类型检查,这样就会变得较为复杂。

    三、组合模式实现方式

    3.1 使用抽象组件类和具体组件类

    // 抽象组件类
    abstract class Component {
        protected String name;
    
        public Component(String name) {
            this.name = name;
        }
    
        public abstract void operation();
    }
    
    // 具体组件类A
    class ConcreteComponentA extends Component {
        public ConcreteComponentA(String name) {
            super(name);
        }
    
        @Override
        public void operation() {
            System.out.println("ConcreteComponentA: " + name);
        }
    }
    
    // 具体组件类B
    class ConcreteComponentB extends Component {
        public ConcreteComponentB(String name) {
            super(name);
        }
    
        @Override
        public void operation() {
            System.out.println("ConcreteComponentB: " + name);
        }
    }
    
    // 组合组件类
    class CompositeComponent extends Component {
        private List<Component> components = new ArrayList<>();
    
        public CompositeComponent(String name) {
            super(name);
        }
    
        public void addComponent(Component component) {
            components.add(component);
        }
    
        public void removeComponent(Component component) {
            components.remove(component);
        }
    
        @Override
        public void operation() {
            System.out.println("CompositeComponent: " + name);
            for (Component component : components) {
                component.operation();
            }
        }
    }
    
    // 客户端代码
    public class Main {
        public static void main(String[] args) {
            CompositeComponent composite = new CompositeComponent("Root");
            Component componentA = new ConcreteComponentA("A");
            Component componentB = new ConcreteComponentB("B");
            composite.addComponent(componentA);
            composite.addComponent(componentB);
            composite.operation();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    3.2 使用接口和实现类

    // 组件接口
    interface Component {
        void operation();
    }
    
    // 具体组件类A
    class ConcreteComponentA implements Component {
        private String name;
    
        public ConcreteComponentA(String name) {
            this.name = name;
        }
    
        @Override
        public void operation() {
            System.out.println("ConcreteComponentA: " + name);
        }
    }
    
    // 具体组件类B
    class ConcreteComponentB implements Component {
        private String name;
    
        public ConcreteComponentB(String name) {
            this.name = name;
        }
    
        @Override
        public void operation() {
            System.out.println("ConcreteComponentB: " + name);
        }
    }
    
    // 组合组件类
    class CompositeComponent implements Component {
        private List<Component> components = new ArrayList<>();
    
        public void addComponent(Component component) {
            components.add(component);
        }
    
        public void removeComponent(Component component) {
            components.remove(component);
        }
    
        @Override
        public void operation() {
            System.out.println("CompositeComponent");
            for (Component component : components) {
                component.operation();
            }
        }
    }
    
    // 客户端代码
    public class Main {
        public static void main(String[] args) {
            CompositeComponent composite = new CompositeComponent();
            Component componentA = new ConcreteComponentA("A");
            Component componentB = new ConcreteComponentB("B");
            composite.addComponent(componentA);
            composite.addComponent(componentB);
            composite.operation();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
  • 相关阅读:
    windows10更新怎么关闭
    Object.defineProperty也能监听数组变化?
    (附源码)计算机毕业设计SSM焦作旅游网站
    .Net之延迟队列
    Redis 数据类型详细解析
    孙卫琴的《精通Vue.js》读书笔记-分割setup()函数
    Redis的下载与安装Windows和Linux版
    图的存储方式
    卷积神经网络吴恩达coursera
    【会话技术基础】
  • 原文地址:https://blog.csdn.net/miaoyl1234/article/details/134259640