十六 结构型-组合模式(Composite)

179 阅读4分钟

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。
小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

image.png 其他设计模式介绍
创建型: 工厂方法 抽象工厂 原型
结构型: 适配器 桥接模式 组合模式 装饰模式 外观模式 享元模式 代理模式
行为型: 职责链 命令 解释器 迭代器 中介者 备忘录 状态模式 策略模式 模板方法 访问者

定义

  • 组合模式实际上就是个树形结构,一棵树的节点如果没有分支,就是叶子节点;如果存在分支,则是树枝节点。

  • 我们平时遇到的最典型的组合结构就是文件和文件夹了,具体的文件就是叶子节点,而文件夹下还可以存在文件和文件夹,所以文件夹一般是树枝节点。

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

image.png

UML

image.png

模式的结构

组合模式包含以下主要角色。

  1. 抽象构件(Component)角色:它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。(总的抽象类或接口,定义一些通用的方法,比如新增、删除)

  2. 树叶构件(Leaf)角色:是组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件。

  3. 树枝构件(Composite)角色 / 中间构件:是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。

示例

//抽象构件
internal interface Component {
    fun add(c: Component)
    fun remove(c: Component)
    fun getChild(i: Int): Component?
    fun operation()
}

//树叶构件
internal class Leaf(private val name: String) : Component {
    override fun add(c: Component) {}
    override fun remove(c: Component) {}
    override fun getChild(i: Int): Component? {
        return null
    }

    override fun operation() {
        println("树叶$name:被访问!")
    }
}

//树枝构件
internal class Composite : Component {
    private val children = ArrayList<Component>()
    override fun add(c: Component) {
        children.add(c)
    }

    override fun remove(c: Component) {
        children.remove(c)
    }

    override fun getChild(i: Int): Component? {
        return children[i]
    }

    override fun operation() {
        for (obj in children) {
            obj.operation()
        }
    }
}

fun main() {
    val c0: Component = Composite()
    val c1: Component = Composite()
    val leaf1: Component = Leaf("1")
    val leaf2: Component = Leaf("2")
    val leaf3: Component = Leaf("3")
    c0.add(leaf1)
    c0.add(c1)
    c1.add(leaf2)
    c1.add(leaf3)
    c0.operation()
} 

程序运行结果如下:

树叶1:被访问!
树叶2:被访问!
树叶3:被访问!

组合模式的应用场景

前面分析了组合模式的结构与特点,下面分析它适用的以下应用场景。

  1. 需要表示一个对象整体或部分层次,在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,可以一致地对待它们。
  2. 要求对用户隐藏组合对象与单个对象的不同,用户可以用统一的接口使用组合结构中的所有对象的场合。
  3. 让客户能够忽略不同对象层次的变化,客户端可以针对抽象构件编程,无须关心对象层次结构的细节。

小结

  1. 组合模式用于将多个对象组合成树形结构以表示“整体-部分”的结构层次。组合模式对单个对象(叶子对象)和组合对象(容器对象)的使用具有一致性。

  2. 组合对象的关键在于它定义了一个抽象构建类,它既可表示叶子对象,也可表示容器对象,客户仅仅需要针对这个抽象构建进行编程,无须知道他是叶子对象还是容器对象,都是一致对待。

  3. 组合模式虽然能够非常好地处理层次结构,也使得客户端程序变得简单,但是它也使得设计变得更加抽象,而且也很难对容器中的构件类型进行限制,这会导致在增加新的构件时会产生一些问题。