携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第二十四天,点击查看活动详情
重学设计模式之组合模式(Kotlin)
前言
组合模式有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦
组合模式(Composite Pattern):将对象组合成树形结构以表示‘部分-整体’的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。
组合模式的角色以及职责
-
Component(抽象构件):一般是接口或者抽象类,是叶子构件和容器构件对象声明接口,抽象出访问以及管理子构件的方法
-
Leaf(叶子构件):在组合中表示叶节点,叶节点没有子节点,定义对象的基本行为
-
Composite(容器构件):容器节点可以包含子节点,子节点可以是叶子节点,也可以是容器节点
实例
我们公司都会又有组织结构,技术部、运营部、市场部、总经办等结构,我们就以这个为例用代码来实现以下。
在组合模式中有两种实现方式:透明模式和安全模式
两者的区别在于透明模式将组合使用的方法放到抽象类中,而安全模式则是放到具体实现类中
透明模式
- 创建抽象构件
Component:
//抽象公司框架结构
abstract class Component(var name: String) {
//创建节点:创建部门或者员工入职
abstract fun add(component: Component)
//删除节点:解散部门或者员工离职
abstract fun remove(component: Component)
//展示
abstract fun show(depth: Int)
}
- 创建容器构件
Composite:
//这里可以表示具体公司框架(公司、部门)
class Composite(name: String) : Component(name) {
var childs: ArrayList<Component> = ArrayList()
override fun add(component: Component) {
childs.add(component)
}
override fun remove(component: Component) {
childs.remove(component)
}
override fun show(depth: Int) {
for (i in 0 until depth) {
print(" ")
}
println("$name: ")
for (component in childs) {
component.show(depth + 1)
}
}
}
- 创建叶子构件
Leaf:
//具体职员
class Leaf(
name: String
) : Component(name) {
override fun add(component: Component) {
}
override fun remove(component: Component) {
}
override fun show(depth: Int) {
for (i in 0 until depth) {
print(" ")
}
println(name)
}
}
- 最后我们来调用一下:
fun main() {
//创建一个公司
val gongsi = Composite("大厂公司")
//创建部门
val zongjingban = Composite("总经办")
val jishub = Composite("技术部")
val yunyingbu = Composite("运营部")
val shichangbu = Composite("市场部")
gongsi.add(zongjingban)
gongsi.add(jishub)
gongsi.add(yunyingbu)
gongsi.add(shichangbu)
//给部门招人
zongjingban.add(Leaf("董事1"))
zongjingban.add(Leaf("董事2"))
zongjingban.add(Leaf("董事3"))
jishub.add(Leaf("程序员1"))
jishub.add(Leaf("程序员2"))
jishub.add(Leaf("程序员3"))
yunyingbu.add(Leaf("运营1"))
yunyingbu.add(Leaf("运营2"))
yunyingbu.add(Leaf("运营3"))
shichangbu.add(Leaf("市场1"))
shichangbu.add(Leaf("市场2"))
shichangbu.add(Leaf("市场3"))
gongsi.show(0)
}
输出:
大厂公司:
总经办:
董事1
董事2
董事3
技术部:
程序员1
程序员2
程序员3
运营部:
运营1
运营2
运营3
市场部:
市场1
市场2
市场3
可以看到以上是一棵树的结果,不管是叶子节点,还是组合节点,都是一样的操作
- 安全模式
就是叶子节点和组合节点的特性分开,只有组合节点才有增加和删除操作,而两者都会拥有展示操作。但是如果同时对外暴露叶子节点和组合节点的话,使用起来还需要做特殊的判断
修改后:
//公司框架结构
abstract class Component(var name: String) {
//展示
abstract fun show(depth: Int)
}
//这里可以表示具体公司框架(公司、部门)
class Composite(name: String) : Component(name) {
var childs: ArrayList<Component> = ArrayList()
fun add(component: Component) {
childs.add(component)
}
fun remove(component: Component) {
childs.remove(component)
}
override fun show(depth: Int) {
for (i in 0 until depth) {
print(" ")
}
println("$name: ")
for (component in childs) {
component.show(depth + 1)
}
}
}
//具体职员
class Leaf(
name: String
) : Component(name) {
override fun show(depth: Int) {
for (i in 0 until depth) {
print(" ")
}
println(name)
}
}
fun main() {
//创建一个公司
val gongsi = Composite("大厂公司")
//创建部门
val zongjingban = Composite("总经办")
val jishub = Composite("技术部")
val yunyingbu = Composite("运营部")
val shichangbu = Composite("市场部")
gongsi.add(zongjingban)
gongsi.add(jishub)
gongsi.add(yunyingbu)
gongsi.add(shichangbu)
//给部门招人
zongjingban.add(Leaf("董事1"))
zongjingban.add(Leaf("董事2"))
zongjingban.add(Leaf("董事3"))
jishub.add(Leaf("程序员1"))
jishub.add(Leaf("程序员2"))
jishub.add(Leaf("程序员3"))
yunyingbu.add(Leaf("运营1"))
yunyingbu.add(Leaf("运营2"))
yunyingbu.add(Leaf("运营3"))
shichangbu.add(Leaf("市场1"))
shichangbu.add(Leaf("市场2"))
shichangbu.add(Leaf("市场3"))
gongsi.show(0)
}
输出:
大厂公司:
总经办:
董事1
董事2
董事3
技术部:
程序员1
程序员2
程序员3
运营部:
运营1
运营2
运营3
市场部:
市场1
市场2
市场3
组合模式优缺点
优点:
-
你可以利用多态和递归机制更方便地使用复杂树结构
-
满足开闭原则 无需更改现有代码, 你就可以在应用中添加新元素, 使其成为对象树的一部分
缺点:
- 对于功能差异较大的类, 提供公共接口或许会有困难。 在特定情况下, 你需要过度一般化组件接口, 使其变得令人难以理解
与其他模式的关系
-
桥接模式和策略模式 (在某种程度上包括适配器模式) 模式的接口非常相似。 实际上, 它们都基于组合模式——即将工作委派给其他对象, 不过也各自解决了不同的问题。 模式并不只是以特定方式组织代码的配方, 你还可以使用它们来和其他开发者讨论模式所解决的问题。
-
责任链模式通常和组合模式结合使用。 在这种情况下, 叶组件接收到请求后, 可以将请求沿包含全体父组件的链一直传递至对象树的底部。
-
组合和装饰模式的结构图很相似, 因为两者都依赖递归组合来组织无限数量的对象。
装饰类似于组合, 但其只有一个子组件。 此外还有一个明显不同: 装饰为被封装对象添加了额外的职责, 组合仅对其子节点的结果进行了 “求和”。
但是, 模式也可以相互合作: 你可以使用装饰来扩展组合树中特定对象的行为。