【Java设计模式】组合模式:构建灵活的树结构

【Java设计模式】组合模式:构建灵活的树结构

一、概述

在Java中,组合模式用于将对象组合成树结构,以表示部分 - 整体层次结构。该模式允许客户端统一对待单个对象和对象的组合。

二、组合设计模式的别名

  • Object Tree(对象树)
  • Composite Structure(组合结构)

三、组合设计模式的意图

将对象组合成树结构,以表示部分 - 整体层次结构。组合设计模式允许客户端统一对待单个对象和对象的组合。

四、组合模式的详细解释及实际示例

  1. 实际示例
    • 在一个现实世界的例子中,考虑一个具有复杂组织结构的公司。该公司由各个部门组成,每个部门可以包含子部门,最终包含单个员工。组合设计模式可以用于表示这种结构。每个部门和员工都被视为树结构中的一个节点,其中部门可以包含其他部门或员工,但员工是没有子节点的叶节点。这允许公司统一执行操作,例如计算总工资或打印组织结构图,通过以相同的方式对待单个员工和整个部门。
  2. 通俗解释
    • 组合设计模式允许客户端统一对待单个对象和对象的组合。
  3. 维基百科解释
    • 在软件工程中,组合模式是一种分区设计模式。组合模式描述了一组对象应被视为单个对象的实例来处理。组合的意图是将对象“组合”成树结构,以表示部分 - 整体层次结构。实现组合模式可以让客户端统一对待单个对象和对象的组合。

五、Java中组合模式的编程示例

每个句子由单词组成,而单词又由字符组成。这些对象中的每一个都是可打印的,并且它们可以在之前或之后打印一些东西,例如句子总是以句号结尾,单词之前总是有空格。
在这里,我们有基类LetterComposite和不同的可打印类型LetterWordSentence

public abstract class LetterComposite {
    private final List<LetterComposite> children = new ArrayList<>();
    public void add(LetterComposite letter) {
        children.add(letter);
    }
    public int count() {
        return children.size();
    }
    protected void printThisBefore() {
    }
    protected void printThisAfter() {
    }
    public void print() {
        printThisBefore();
        children.forEach(LetterComposite::print);
        printThisAfter();
    }
}
public class Letter extends LetterComposite {
    private final char character;
    public Letter(char c) {
        this.character = c;
    }
    @Override
    protected void printThisBefore() {
        System.out.print(character);
    }
}
public class Word extends LetterComposite {
    public Word(List<Letter> letters) {
        letters.forEach(this::add);
    }
    public Word(char... letters) {
        for (char letter : letters) {
            this.add(new Letter(letter));
        }
    }
    @Override
    protected void printThisBefore() {
        System.out.print(" ");
    }
}
public class Sentence extends LetterComposite {
    public Sentence(List<Word> words) {
        words.forEach(this::add);
    }
    @Override
    protected void printThisAfter() {
        System.out.print(".");
    }
}

然后我们有一个信使来传递消息:

public class Messenger {
    LetterComposite messageFromOrcs() {
        var words = List.of(
                new Word('W', 'h', 'e', 'r', 'e'),
                new Word('t', 'h', 'e', 'r', 'e'),
                new Word('i', 's'),
                new Word('a'),
                new Word('w', 'h', 'i', 'p'),
                new Word('t', 'h', 'e', 'r', 'e'),
                new Word('i', 's'),
                new Word('a'),
                new Word('w', 'a', 'y')
        );
        return new Sentence(words);
    }
    LetterComposite messageFromElves() {
        var words = List.of(
                new Word('M', 'u', 'c', 'h'),
                new Word('w', 'i', 'n', 'd'),
                new Word('p', 'o', 'u', 'r', 's'),
                new Word('f', 'r', 'o', 'm'),
                new Word('y', 'o', 'u', 'r'),
                new Word('m', 'o', 'u', 't', 'h')
        );
        return new Sentence(words);
    }
}

然后可以这样使用:

  public static void main(String[] args) {
    var messenger = new Messenger();
    LOGGER.info("Message from the orcs: ");
    messenger.messageFromOrcs().print();
    LOGGER.info("Message from the elves: ");
    messenger.messageFromElves().print();
}

控制台输出:

20:43:54.801 [main] INFO com.iluwatar.composite.App -- Message from the orcs: 
 Where there is a whip there is a way.
20:43:54.803 [main] INFO com.iluwatar.composite.App -- Message from the elves: 
 Much wind pours from your mouth.

六、何时在Java中使用组合模式

当出现以下情况时使用组合模式:

  1. 您想要表示对象的部分 - 整体层次结构。
  2. 您希望客户端能够忽略对象组合和单个对象之间的区别。客户端将统一对待组合结构中的所有对象。

七、组合模式在Java中的实际应用

  1. 图形用户界面,其中组件可以包含其他组件(例如,包含按钮、标签、其他面板的面板)。
  2. 文件系统表示,其中目录可以包含文件和其他目录。
  3. 组织结构,其中一个部门可以包含子部门和员工。
  4. java.awt.Containerjava.awt.Component
  5. Apache Wicket组件树,参见[Component](https://github.com/apache/wicket/blob/91e154702ab1ff3481ef6cbb04c6044814b7e130/wicket - core/src/main/java/org/apache/wicket/Component.java)和[MarkupContainer](https://github.com/apache/wicket/blob/b60ec64d0b50a611a9549809c9ab216f0ffa3ae3/wicket - core/src/main/java/org/apache/wicket/MarkupContainer.java)

八、组合模式的优点和权衡

优点:

  1. 简化了客户端代码,因为它可以统一对待组合结构和单个对象。
  2. 更容易添加新的组件类型,因为现有的代码不需要更改。

权衡:

  1. 可能会使设计过于通用。可能难以限制组合的组件。
  2. 可能会使限制组合中组件的类型变得更加困难。

九、源码下载

组合模式示例代码下载

通过本文的介绍,相信大家对Java中的组合模式有了更深入的了解。在实际开发中,合理运用组合模式可以构建灵活的树结构,提高代码的可扩展性和可维护性。

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值