zoukankan      html  css  js  c++  java
  • DesignPatternCompisite组合模式

    DesignPatternCompisite组合模式

    组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。

    这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。

    官方代码1

    package composite
    
    import "fmt"
    
    type Component interface {
    	Parent() Component
    	SetParent(Component)
    	Name() string
    	SetName(string)
    	AddChild(Component)
    	Print(string)
    }
    
    const (
    	LeafNode = iota
    	CompositeNode
    )
    
    func NewComponent(kind int, name string) Component {
    	var c Component
    	switch kind {
    	case LeafNode:
    		c = NewLeaf()
    	case CompositeNode:
    		c = NewComposite()
    	}
    
    	c.SetName(name)
    	return c
    }
    
    type component struct {
    	parent Component
    	name   string
    }
    
    func (c *component) Parent() Component {
    	return c.parent
    }
    
    func (c *component) SetParent(parent Component) {
    	c.parent = parent
    }
    
    func (c *component) Name() string {
    	return c.name
    }
    
    func (c *component) SetName(name string) {
    	c.name = name
    }
    
    func (c *component) AddChild(Component) {}
    
    func (c *component) Print(string) {}
    
    type Leaf struct {
    	component
    }
    
    func NewLeaf() *Leaf {
    	return &Leaf{}
    }
    
    func (c *Leaf) Print(pre string) {
    	fmt.Printf("%s-%s
    ", pre, c.Name())
    }
    
    type Composite struct {
    	component
    	childs []Component
    }
    
    func NewComposite() *Composite {
    	return &Composite{
    		childs: make([]Component, 0),
    	}
    }
    
    func (c *Composite) AddChild(child Component) {
    	child.SetParent(c)
    	c.childs = append(c.childs, child)
    }
    
    func (c *Composite) Print(pre string) {
    	fmt.Printf("%s+%s
    ", pre, c.Name())
    	pre += " "
    	for _, comp := range c.childs {
    		comp.Print(pre)
    	}
    }
    
    func Tm() {
    	root := NewComponent(CompositeNode, "root")
    	c1 := NewComponent(CompositeNode, "c1")
    	c2 := NewComponent(CompositeNode, "c2")
    	c3 := NewComponent(CompositeNode, "c3")
    
    	l1 := NewComponent(LeafNode, "l1")
    	l2 := NewComponent(LeafNode, "l2")
    	l3 := NewComponent(LeafNode, "l3")
    
    	root.AddChild(c1)
    	root.AddChild(c2)
    
    	c1.AddChild(c3)
    	c1.AddChild(l1)
    
    	c2.AddChild(l2)
    	c2.AddChild(l3)
    
    	root.Print("")
    }
    
    
    # 测试文件
    package component
    
    import "testing"
    
    func TestTTmain(t *testing.T) {
    	TTTmain()
    }
    
    
    #输出
    +root
     +c1
      +c3
      -l1
     +c2
      -l2
      -l3
    

    官方代码2(来自B站蜡笔小程序员)

    他的这个我不太喜欢

    package Composite
    
    import "fmt"
    
    type Component interface {
    	Traverse()
    }
    
    type Leaf struct {
    	value int
    }
    
    func NewLeaf(value int) *Leaf {
    	return &Leaf{value}
    }
    
    func (l *Leaf) Traverse() {
    	fmt.Println(l.value)
    }
    
    type Composite struct {
    	children []Component
    }
    
    func NewComposite() *Composite {
    	return &Composite{children: make([]Component, 0)}
    }
    
    func (c *Composite) Add(component Component) {
    	c.children = append(c.children, component)
    }
    
    func (c *Composite) Traverse() {
    	for idx, _ := range c.children {
    		c.children[idx].Traverse()
    	}
    }
    
    
    # 测试代码
    package Composite
    
    import (
    	"fmt"
    	"testing"
    )
    
    func TestComposite_Traverse(t *testing.T) {
    	containers := make([]Composite, 4)
    	for i := 0; i < 4; i++ {
    		for j := 0; j < 3; j++ {
    			containers[i].Add(NewLeaf(i*3 + j))
    		}
    	}
    	for i := 1; i < 4; i++ {
    		containers[0].Add(&(containers[i]))
    	}
    	for i := 0; i < 4; i++ {
    		containers[i].Traverse()
    		fmt.Printf("
    ")
    	}
    }
    

    毛哥实际业务场景模拟

    • 模拟实现文件层级结构
    • 分析可知,文件系统只有文件夹可以是父亲节点
    • 这在设置父亲节时候,可以很方便
    • 对应官方的就是文件夹 -> Composite, 文件 -> Leaf
    package component
    
    import "fmt"
    
    // 文件系统展开
    // 文件夹是继续展开
    // 文件是输出内容
    type IFiler interface {
    	// 为孩子设置父亲节点为自己
    	SetParent(fa IFiler)
    	// 获取父亲节点的名字
    	GetParentName() string
    	// 打印文件包括文件夹
    	Fopen()
    }
    
    // 文件夹
    type Floder struct {
    	// 文件夹名称
    	Name string
    	Parent IFiler
    	// 文件夹的孩子可以是文件或者文件夹,所以用接口替代
    	Childs []IFiler
    }
    
    func NewFloder(n string) *Floder {
    	return &Floder{
    		Name:   n,
    		Childs: make([]IFiler, 0),
    	}
    }
    
    // 如果是文件就继续打开,如果是文件就输出里面内容
    func (f *Floder) Fopen() {
    	for _, v := range f.Childs {
    		fmt.Println(f.Name,"父亲节点是", f.GetParentName())
    		v.Fopen()
    	}
    }
    
    func (f *Floder) AddChilds(fi IFiler) {
    	f.SetParent(fi)
    
    	f.Childs = append(f.Childs, fi)
    }
    
    // son设置父亲节点为f
    func (f *Floder) SetParent(son IFiler) {
    	switch son.(type) {
    	case *Floder:
    		floder := son.(*Floder)
    		floder.Parent = f
    	case *FileReal:
    		fileReal := son.(*FileReal)
    		fileReal.Parent = f
    	}
    }
    
    func (f *Floder) GetParentName() string {
    	floder := f.Parent.(*Floder)
    	return floder.Name
    }
    
    type FileReal struct {
    	Name string
    	Parent IFiler
    	Value int // 模拟文件里面的数据
    }
    
    func NewFildReal(n string, v int) *FileReal {
    	return &FileReal{
    		Name:  n,
    		Value: v,
    	}
    }
    
    // 因为是文件,打不开了所以直接输出内容
    func (f *FileReal) Fopen() {
    	fmt.Println(f.Name, f.Value, "---父亲节点是:", f.GetParentName())
    }
    
    func (f *FileReal) SetParent(fa IFiler) {
    }
    
    func (f *FileReal) GetParentName() string {
    	floder := f.Parent.(*Floder)
    	return floder.Name
    }
    
    func TTTmain() {
    	nul := NewFloder("nul")
    	root := NewFloder("root")
    
    	one := NewFloder("one")
    	two := NewFloder("two")
    
    	h1 := NewFloder("h1")
    	h2 := NewFloder("h2")
    
    	f1 := NewFildReal("f1", 10)
    	f2 := NewFildReal("f2", 20)
    
    	nul.AddChilds(root)
    
    	root.AddChilds(one)
    	root.AddChilds(two)
    
    	one.AddChilds(h1)
    	two.AddChilds(h2)
    
    	h1.AddChilds(f1)
    	h2.AddChilds(f2)
    
    	one.Fopen()
    }
    
    # 根据最后的tttmain()输出
    one 父亲节点是 root
    h1 父亲节点是 one
    f1 10 ---父亲节点是: h1
    

    总结

    这些模式和那个数据结构树很相似,这里面用的是切片,树用的是链表

  • 相关阅读:
    获取表信息(MSSQL)
    合并有数据的列
    isnull的使用方法
    查询SQLServer的启动时间
    查询数据库中有数据的表
    查询数据库中表使用的空间信息。
    SQL Server SA 密码丢失无法连接数据库怎么办?
    tensorflow 语法及 api 使用细节
    Python: PS 滤镜-- Fish lens
    中英文对照 —— 概念的图解
  • 原文地址:https://www.cnblogs.com/maomaomaoge/p/14184523.html
Copyright © 2011-2022 走看看