组合模式是一种结构型设计模式,你可以使用它将对象组合成树状结构,并且能像使用独立对象一样使用它们。
解决什么问题?
如果类的结构层次像树状结构一样,使用组合模式则是一个很好的方式。
实现步骤:
- 定义接口
- 定义树节点和实体类,树节点包含实体类。
- 构建树
优势:
- 你可以利用多态和递归机制更方便地使用复杂树结构。
- 开闭原则。 无需更改现有代码, 你就可以在应用中添加新元素, 使其成为对象树的一部分。
劣势:
- 对于功能差异较大的类,提供公共接口或许会有困难。在特定情况下,你需要过度一般化组件接口,使其变得令人难以理解。
下面是实例代码:
package main
import "fmt"
type draw interface{ draw() bool }
type node struct {
children []draw
name string
d draw
}
func (n *node) draw() bool {
if n.d != nil {
return n.d.draw()
}
return false
}
type shape struct{}
func (s *shape) draw() bool { return false }
type circle struct{}
func (c *circle) draw() bool {
fmt.Println("draw shape circle")
return true
}
type color struct{}
func (c *color) draw() bool { return false }
type red struct{}
func (r *red) draw() bool {
fmt.Println("draw color red")
return true
}
func newNode(name string, d draw) *node {
return &node{
children: make([]draw, 0),
name: name,
d: d,
}
}
var root = node{
children: make([]draw, 0),
name: "root",
d: draw(nil),
}
// 构建树状结构
func init() {
circleNode := newNode("circle", &circle{})
shapeNode := newNode("shape", nil)
shapeNode.children = append(shapeNode.children, circleNode)
root.children = append(root.children, shapeNode)
redNode := newNode("red", &red{})
colorNode := newNode("color", nil)
colorNode.children = append(colorNode.children, redNode)
root.children = append(root.children, colorNode)
}
// 递归查找节点
func drawSomething(root *node, name string) bool {
if root == nil {
return false
}
if root.name == name {
return root.draw()
}
for _, v := range root.children {
n, ok := v.(*node)
if !ok {
continue
}
if ret := drawSomething(n, name); ret {
return ret
}
}
return false
}
func main() {
// 下面3个调用不会输出任何东西
drawSomething(&root, "notInTree")
drawSomething(&root, "shape")
drawSomething(&root, "color")
drawSomething(&root, "circle")
drawSomething(&root, "red")
}
输出:
draw shape circle
draw color red