第十一章:组合模式

一、情景

Tony作为一名合格软件工程师要学会组装一台自己的电脑。一台电脑的组成:主板、电源,而主板上又有CPU、硬盘、显卡。显示器需要单独插电源才能工作。

程序模拟场景

package main

import "fmt"

/********************************基础组件**********************************************/

type ComputerComponent struct {
    name string
}

func (c *ComputerComponent) isComposite() bool {
    return false
}

func (c *ComputerComponent)startUp(indent string){
    fmt.Printf("%s%s准备开始工作...\n",indent, c.name)
}

func (c *ComputerComponent)shutdown(indent string){
    fmt.Printf("%s%s即将结束工作...\n", indent,c.name)
}

func NewComponent(name string)*ComputerComponent{
    return &ComputerComponent{
        name: name,
    }
}

/********************************实际组件**********************************************/

type CPU struct {
    /*处理器*/
    *ComputerComponent
}

func (c *CPU)showInfo(indent string){
    fmt.Printf("%sCPU:%s, 可以进行高速计算。\n",indent, c.name)
}

func NewCpu(name string) *CPU{
    return &CPU{
        ComputerComponent:NewComponent(name),
    }
}

type MemoryCard struct {
    /*内存*/
    *ComputerComponent
}

func NewMemory(name string) *MemoryCard {
    return &MemoryCard{
        ComputerComponent:NewComponent(name),
    }
}

func (m *MemoryCard)showInfo(indent string){
    fmt.Printf("%s内存:%s,可以缓存数据,读写速度块。\n", indent, m.name)
}

type HardDisk struct {
    /*硬盘*/
    *ComputerComponent
}

func (h *HardDisk)showInfo(indent string){
    fmt.Printf("%s硬盘:%s,可以永久存储数据,容量大。\n",indent,h.name)
}

func NewHardDisk(name string) *HardDisk{
    return &HardDisk{
        ComputerComponent:NewComponent(name),
    }
}

type GraphicsCard struct {
    /*显卡*/
    *ComputerComponent
}

func (g *GraphicsCard)showInfo(indent string){
    fmt.Printf("%s显卡:%s,可以高速计算和处理图形图像。\n",indent,g.name)
}

func NewGraphics(name string)* GraphicsCard{
    return &GraphicsCard{
        ComputerComponent:NewComponent(name),
    }
}

type Battery struct {
    /*电源*/
    *ComputerComponent
}

func (b *Battery)showInfo(indent string){
    fmt.Printf("%s电源:%s,可以持续给主板和外接配件供电。\n",indent)
}

func NewBattery(name string) *Battery {
    return &Battery{
        ComputerComponent:NewComponent(name),
    }
}

type Fan struct {
    /*风扇*/
    *ComputerComponent
}

func (f *Fan)showInfo(indent string){
    fmt.Printf("%s风扇:%s,辅助CPU散热。\n",indent,f.name)
}

func NewFan(name string)*Fan{
    return &Fan{
        ComputerComponent:NewComponent(name),
    }
}

type DisPlayer struct {
    /*显示器*/
    *ComputerComponent
}

func (d *DisPlayer)showInfo(indent string){
    fmt.Printf("%s显示器:%s,负责内容的显示。\n",indent,d.name)
}

func NewDisPlayer(name string) *DisPlayer {
    return &DisPlayer{
        ComputerComponent:NewComponent(name),
    }
}

/**********************************抽象组件********************************************/

type Part interface {
    showInfo(indent string)
    startUp(indent string)
    shutdown(indent string)
}

/***********************************配件组合器*******************************************/

type ComputerComposite struct {
    /*配件组合器*/
    *ComputerComponent
    Components []Part
}

func (c *ComputerComposite)showInfo(indent string){
    fmt.Printf("%s,由以下部件组成:\n", c.name)
    indent += "\t"
    for i:=0;i

输出结果:

电脑:Tony DIY 电脑,由以下部件组成:
    机箱:SAMA MATX,由以下部件组成:
        主板:GIGABYTE Z170M M-atx,由以下部件组成:
            CPU:Intel core I5-6600k, 可以进行高速计算。
            内存:Kingston Fury DDR4,可以缓存数据,读写速度块。
            硬盘:Kingston v300,可以永久存储数据,容量大。
            显卡:Colorful iGame750,可以高速计算和处理图形图像。
        电源:%!s(MISSING),可以持续给主板和外接配件供电。
        风扇:DEEPCOOL 120T,辅助CPU散热。
    显示器:AOC Lv243xip,负责内容的显示。

开机过程:
Tony DIY 电脑准备开始工作...
    SAMA MATX准备开始工作...
        GIGABYTE Z170M M-atx准备开始工作...
            Intel core I5-6600k准备开始工作...
            Kingston Fury DDR4准备开始工作...
            Kingston v300准备开始工作...
            Colorful iGame750准备开始工作...
        Antec vp 450p准备开始工作...
        DEEPCOOL 120T准备开始工作...
    AOC Lv243xip准备开始工作...

关机过程:
Tony DIY 电脑即将结束工作...
    SAMA MATX即将结束工作...
        GIGABYTE Z170M M-atx即将结束工作...
            Intel core I5-6600k即将结束工作...
            Kingston Fury DDR4即将结束工作...
            Kingston v300即将结束工作...
            Colorful iGame750即将结束工作...
        Antec vp 450p即将结束工作...
        DEEPCOOL 120T即将结束工作...
    AOC Lv243xip即将结束工作...

Process finished with exit code 0

二、从剧情中思考什么是组合模式

2.1什么是组合模式

将对象组合成树形结构以表示“整体-部分”的层次结构关系。组合使得用户对单个对象和复合对象的使用具有一致性。
组合模式使得用户对单个对象和组合对象的使用具有一致性(如源码示例中 startup与shutdown的使用),使用组合对象就像使用一般对象一样,不用关心内部的组织结构。

2.2组合模式的设计思想

Tony自己DIY组装的电脑是由各个配件组成的,在组装之前,就是单个CPU、硬盘、显卡等配件,不能称为电脑,只有把它们按正确的方式组装在一起,配合操作系统才能正常运行。一般人使用电脑并不会关注内部的结构,只会关注一台整机。
组装的电脑具有明显的部分与整体的关系,主板、电源等是电脑的一部分,而主板上又有CPU、硬盘、显卡,它们又是主板的一部分。像电脑一样,把对象组合成树形结构,以表示“部分-整体”的层次结构的程序设计模式就叫组合模式

台式机的组成.png

我们将这种层次关系转换成对象的组合关系,如下图
组合关系.png

三、模型抽象

组合模式的类图.png

Component是组件的基类,定义统一的方法feature()和isComposite(),isComposite()用于判断一个组件是否为复合组件。ComponentImplA 和 ComponentImplB 是具体的组件。Composite就是复合组件(也就是组合对象),复合组件可以添加或删除组件,CompositeImplA 和CompositeImplB是具体的复合组件。复合组件本身也是一个组件,因此组合对象可以像一般对象一样被使用,因为它也实现了Component的feature()方法。

3.1模型说明

1.设计要点
在设计迭代器模式时,要注意以下两点:
(1)理清部分与整体的关系,了解对象的组成结构。
(2)组合模式是一种具有层次关系的树形结构,不能再分的叶子节点是具体的组件,也就是最小的逻辑单元;具有子节点(由多个子组件组成)的组件称为复合组件,也就是组合对象。
2.组合模式的优缺点
优点:
(1)调用简单,组合对象可以像一般对象一样使用。
(2)组合对象可以自由地增加、删除组件,可灵活地组合不同的对象。
缺点:
在一些层次结构太深的场景中,组合结构会变得太庞杂。

四、应用场景

  1. 对象之间具有明显的“部分-整体”的关系时,或者具有层次关系时。
  2. 组合对象与单个对象具有相同或者类似行为(方法),用户希望统一地使用组合结构中的所有对象

你可能感兴趣的:(第十一章:组合模式)