前言
组合模式也称为部分整体模式,结构型设计模式之一;
定义:
将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性;
使用场景:
- 表示对象的部分-整体的层次结构时;
- 从一个整体中能够独立出部分模块或功能的场景;
安全的组合模式
安全组合模式的UML类图:
Component:
抽象根节点,对组合中的对象声明接口。在适当的情况下,实现所有类共有接口的缺省行为。声明一个接口用于访问和管理Component的子节点。可在递归结构中定义一个接口,用于访问一个父节点,并在合适的情况下实现它。
Composite:
定义有子节点的那些枝干节点的行为,存储子节点,在Component
接口中实现与子节点有关的操作;
Leaf:
在组合中表示叶子节点对象,叶子节点没有子节点,在组合中定义节点对象的行为;
Client:
通过Component
接口操纵组合节点的对象;
模板代码
- 定义抽象根节点,
Component
abstract class Component(val name: String) {
/**
* 具体的逻辑交给子节点实现
*/
abstract fun doSomething()
}
- 定义具体枝干节点,
Composite
class Composite(name: String) : Component(name) {
//存储节点的容器
private val components = arrayListOf<Component>()
override fun doSomething() {
println("枝干节点名称:$name")
for (component in components) {
component.doSomething()
}
}
/**
* 添加子节点
* @param c 子节点
*/
fun addChild(c: Component) {
components.add(c)
}
/**
* 获取子节点
* @param index 子节点对应下标
*/
fun getChildren(index: Int) {
components[index]
}
/**
* 移除子节点
* @param c 子节点
*/
fun removeChild(c: Component) {
components.remove(c)
}
}
- 定义叶子节点,
Leaf
class Leaf(name: String) : Component(name) {
override fun doSomething() {
println("叶子节点名称:$name")
}
}
- 编写调用测试类
object Test {
@JvmStatic
fun main(args: Array<String>) {
//构造一个根节点
val root = Composite("root")
//构造两个枝干节点
val branch1 = Composite("branch1")
val branch2 = Composite("branch2")
//构造叶子节点
val leaf1 = Leaf("leaf1")
val leaf2 = Leaf("leaf2")
val leaf3 = Leaf("leaf3")
val leaf4 = Leaf("leaf4")
//添加叶子节点
branch1.addChild(leaf1)
branch1.addChild(leaf2)
branch2.addChild(leaf3)
branch2.addChild(leaf4)
//添加枝干节点
root.addChild(branch1)
root.addChild(branch2)
root.doSomething()
}
}
结果输出:
枝干节点名称:root
枝干节点名称:branch1
叶子节点名称:leaf1
叶子节点名称:leaf2
枝干节点名称:branch2
叶子节点名称:leaf3
叶子节点名称:leaf4
优点:
结构清晰明了,逻辑容易理解;
缺点:
违背依赖倒置原则,定义的抽象Component
在调用时并没有起到作用,而是直接依赖的具体细节类;
我们将组合所使用到的方法addChild、removeChild、getChild
定义到抽象类中,得到的是透明的组合模式
透明的组合模式
透明组合模式UML类图:
模板代码
- 定义抽象根节点,
Component
abstract class Component(val name: String) {
/**
* 具体的逻辑交给子节点实现
*/
abstract fun doSomething()
/**
* 添加子节点
*/
abstract fun addChild(c: Component)
/**
* 移除子节点
*/
abstract fun removeChild(c: Component)
/**
* 获取子节点
*/
abstract fun getChildren(index: Int)
}
- 定义具体枝干节点,
Composite
class Composite(name: String) : Component(name) {
//存储节点的容器
private val components = arrayListOf<Component>()
override fun doSomething() {
println("枝干节点名称:$name")
for (component in components) {
component.doSomething()
}
}
/**
* 添加子节点
* @param c 子节点
*/
override fun addChild(c: Component) {
components.add(c)
}
/**
* 获取子节点
* @param index 子节点对应下标
*/
override fun getChildren(index: Int) {
components[index]
}
/**
* 移除子节点
* @param c 子节点
*/
override fun removeChild(c: Component) {
components.remove(c)
}
}
- 定义叶子节点,
Leaf
class Leaf(name: String) : Component(name) {
override fun doSomething() {
println("叶子节点名称:$name")
}
override fun addChild(c: Component) {
throw UnsupportedOperationException("叶子节点没有子节点")
}
override fun removeChild(c: Component) {
throw UnsupportedOperationException("叶子节点没有子节点")
}
override fun getChildren(index: Int) {
throw UnsupportedOperationException("叶子节点没有子节点")
}
}
- 编写测试类
object Test {
@JvmStatic
fun main(args: Array<String>) {
//构造一个根节点
val root = Composite("root") as Component
//构造两个枝干节点
val branch1 = Composite("branch1") as Component
val branch2 = Composite("branch2") as Component
//构造叶子节点
val leaf1 = Leaf("leaf1") as Component
val leaf2 = Leaf("leaf2") as Component
val leaf3 = Leaf("leaf3") as Component
val leaf4 = Leaf("leaf4") as Component
//添加叶子节点
branch1.addChild(leaf1)
branch1.addChild(leaf2)
branch2.addChild(leaf3)
branch2.addChild(leaf4)
//添加枝干节点
root.addChild(branch1)
root.addChild(branch2)
root.doSomething()
}
}
结果输出:
枝干节点名称:root
枝干节点名称:branch1
叶子节点名称:leaf1
叶子节点名称:leaf2
枝干节点名称:branch2
叶子节点名称:leaf3
叶子节点名称:leaf4
优点:
满足依赖倒置原则,细节依赖于抽象;
缺点:
叶子节点没有子节点,无法操作,覆盖的抽象方法是多余的;
Android源码中的组合模式
View树结构
总结
优点:
组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让高层模块忽略了层次的差异,方便对整个层次结构进行控制;
缺点:
在新增构件时不好对枝干中的构件类型进行限制,不能依赖类型系统来施加约束,因为大多情况下,他们都来自于相同的抽象层;
结语
如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )