设计模式笔记 - 组合模式

163 阅读2分钟

组合模式是一种结构型设计模式,你可以使用它将对象组合成树状结构,并且能像使用独立对象一样使用它们。


解决什么问题?

如果类的结构层次像树状结构一样,使用组合模式则是一个很好的方式。


实现步骤:

  • 定义接口
  • 定义树节点和实体类,树节点包含实体类。
  • 构建树

优势:

  • 你可以利用多态和递归机制更方便地使用复杂树结构。
  • 开闭原则。 无需更改现有代码, 你就可以在应用中添加新元素, 使其成为对象树的一部分。

劣势:

  • 对于功能差异较大的类,提供公共接口或许会有困难。在特定情况下,你需要过度一般化组件接口,使其变得令人难以理解。

下面是实例代码:

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

参考