八、结构型(组合模式)

组合模式

概念

组合模式(Composite Pattern)是一种结构型设计模式,允许你将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得客户端可以统一对待单个对象和组合对象。


应用场景

  1. 树形结构表示:适用于需要以树形结构表示对象层次的场景,例如文件系统、组织结构图、UI组件树等。
  2. 处理部分和整体的一致性:在需要统一处理单个对象和组合对象的情况下,组合模式可以简化客户端代码,因为客户端无需关心处理的对象是单个还是组合对象。
  3. 递归操作:适用于需要对树形结构中的所有节点进行递归操作的场景,例如遍历整个树形结构、计算总值、查找等。

注意点

  • 透明性与安全性权衡:组合模式有两种实现方式,透明组合和安全组合。透明组合允许所有组件具有相同接口,操作更统一,但会有不适用的操作(如对叶子节点调用添加子节点的操作)。安全组合则为叶子和组合节点提供不同接口,但操作灵活性降低。
  • 性能问题:由于组合模式需要递归地处理整个树形结构,因此在大规模树形结构中可能存在性能问题。
  • 节点间的职责分配:确保合理分配叶子节点和组合节点的职责,避免职责不明确。

核心要素

  1. Component(抽象构件):定义叶子节点和组合节点的共同接口。
  2. Leaf(叶子节点):表示树形结构的基本元素,不包含子节点。
  3. Composite(组合节点):表示有子节点的复杂元素,包含添加、删除和遍历子节点的功能。
  4. 统一处理:客户端可以统一处理单个对象和组合对象。

Java代码完整示例

java 复制代码
// 抽象构件
interface Component {
    void operation();
}

// 叶子节点
class Leaf implements Component {
    private String name;

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

    @Override
    public void operation() {
        System.out.println("叶子 " + name + " 被访问");
    }
}

// 组合节点
class Composite implements Component {
    private List<Component> children = new ArrayList<>();

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

    public void remove(Component component) {
        children.remove(component);
    }

    public Component getChild(int i) {
        return children.get(i);
    }

    @Override
    public void operation() {
        System.out.println("组合节点被访问");
        for (Component child : children) {
            child.operation();
        }
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        // 创建叶子节点
        Leaf leaf1 = new Leaf("1");
        Leaf leaf2 = new Leaf("2");
        Leaf leaf3 = new Leaf("3");

        // 创建组合节点
        Composite composite = new Composite();
        composite.add(leaf1);
        composite.add(leaf2);

        Composite root = new Composite();
        root.add(composite);
        root.add(leaf3);

        // 统一调用组合结构
        root.operation();
    }
}

输出

组合节点被访问
组合节点被访问
叶子 1 被访问
叶子 2 被访问
叶子 3 被访问

各种变形用法完整示例

  1. 透明组合模式

    在这种实现方式中,叶子和组合节点共享相同的接口,客户端可以透明地使用组合和叶子对象。

    代码示例

    java 复制代码
    // 抽象构件(透明组合)
    interface Component {
        void operation();
        void add(Component component);
        void remove(Component component);
        Component getChild(int i);
    }
    
    // 叶子节点(透明组合)
    class Leaf implements Component {
        private String name;
    
        public Leaf(String name) {
            this.name = name;
        }
    
        @Override
        public void operation() {
            System.out.println("叶子 " + name + " 被访问");
        }
    
        @Override
        public void add(Component component) {
            throw new UnsupportedOperationException("叶子节点不支持添加操作");
        }
    
        @Override
        public void remove(Component component) {
            throw new UnsupportedOperationException("叶子节点不支持删除操作");
        }
    
        @Override
        public Component getChild(int i) {
            throw new UnsupportedOperationException("叶子节点没有子节点");
        }
    }
    
    // 组合节点(透明组合)
    class Composite implements Component {
        private List<Component> children = new ArrayList<>();
    
        @Override
        public void operation() {
            System.out.println("组合节点被访问");
            for (Component child : children) {
                child.operation();
            }
        }
    
        @Override
        public void add(Component component) {
            children.add(component);
        }
    
        @Override
        public void remove(Component component) {
            children.remove(component);
        }
    
        @Override
        public Component getChild(int i) {
            return children.get(i);
        }
    }
    
    // 客户端
    public class ClientTransparentComposite {
        public static void main(String[] args) {
            Component leaf1 = new Leaf("1");
            Component leaf2 = new Leaf("2");
            Component leaf3 = new Leaf("3");
    
            Composite composite = new Composite();
            composite.add(leaf1);
            composite.add(leaf2);
    
            Composite root = new Composite();
            root.add(composite);
            root.add(leaf3);
    
            root.operation();
        }
    }
  2. 安全组合模式

    在安全组合模式下,叶子节点和组合节点有各自不同的接口,避免了客户端对叶子节点调用不适用的操作。

    代码示例

    java 复制代码
    // 抽象构件
    interface Component {
        void operation();
    }
    
    // 叶子节点(安全组合)
    class Leaf implements Component {
        private String name;
    
        public Leaf(String name) {
            this.name = name;
        }
    
        @Override
        public void operation() {
            System.out.println("叶子 " + name + " 被访问");
        }
    }
    
    // 组合节点(安全组合)
    class Composite implements Component {
        private List<Component> children = new ArrayList<>();
    
        public void add(Component component) {
            children.add(component);
        }
    
        public void remove(Component component) {
            children.remove(component);
        }
    
        public Component getChild(int i) {
            return children.get(i);
        }
    
        @Override
        public void operation() {
            System.out.println("组合节点被访问");
            for (Component child : children) {
                child.operation();
            }
        }
    }
    
    // 客户端
    public class ClientSafeComposite {
        public static void main(String[] args) {
            Leaf leaf1 = new Leaf("1");
            Leaf leaf2 = new Leaf("2");
            Leaf leaf3 = new Leaf("3");
    
            Composite composite = new Composite();
            composite.add(leaf1);
            composite.add(leaf2);
    
            Composite root = new Composite();
            root.add(composite);
            root.add(leaf3);
    
            root.operation();
        }
    }
  3. 组合模式与职责链模式结合

    组合模式与职责链模式可以结合使用,使得组合结构的每个节点都有机会处理请求。

    代码示例

    java 复制代码
    // 抽象构件
    interface Component {
        void operation();
        void setNext(Component next);
    }
    
    // 叶子节点(与职责链模式结合)
    class Leaf implements Component {
        private String name;
        private Component next;
    
        public Leaf(String name) {
            this.name = name;
        }
    
        @Override
        public void operation() {
            System.out.println("叶子 " + name + " 被访问");
            if (next != null) {
                next.operation();
            }
        }
    
        @Override
        public void setNext(Component next) {
            this.next = next;
        }
    }
    
    // 组合节点
    class Composite implements Component {
        private List<Component> children = new ArrayList<>();
        private Component next;
    
        public void add(Component component) {
            children.add(component);
        }
    
        @Override
        public void operation() {
            System.out.println("组合节点被访问");
            for (Component child : children) {
                child.operation();
            }
            if (next != null) {
                next.operation();
            }
        }
    
        @Override
        public void setNext(Component next) {
            this.next = next;
        }
    }
    
    // 客户端
    public class ClientChainComposite {
        public static void main(String[] args) {
            Leaf leaf1 = new Leaf("1");
            Leaf leaf2 = new Leaf("2");
    
            Composite composite = new Composite();
            composite.add(leaf1);
            composite.add(leaf2);
    
            Leaf leaf3 = new Leaf("3");
            composite.setNext(leaf3);
    
            composite.operation();
        }
    }

这些示例展示了组合模式的基本用法及其多种变形。

相关推荐
XYX的Blog2 天前
设计模式06-结构型模式1(适配器/桥接/组合模式/Java)
java·设计模式·组合模式
X先生__10 天前
基于SpringBoot设计模式之结构型设计模式·组合模式
spring boot·设计模式·组合模式
麦克·唐18 天前
组合模式(C++)
开发语言·c++·组合模式
前端拾光者19 天前
前端开发设计模式——组合模式
前端·javascript·设计模式·组合模式
树下的码农22 天前
组合模式详解
组合模式
刷帅耍帅25 天前
设计模式-组合模式
设计模式·组合模式
且随疾风前行.1 个月前
技术成神之路:设计模式(十七)组合模式
设计模式·组合模式
思忖小下1 个月前
c#代码介绍23种设计模式_10组合模式
设计模式·c#·组合模式
John_ToDebug1 个月前
设计模式之组合模式
c++·设计模式·组合模式