zoukankan      html  css  js  c++  java
  • Composite——设计模式学习笔记

    Composite模式

    一 意图

      将对象组合成树形结构以表示“部分——整体”的层次结构。Composite使得用户对单个对象操作和组合对象的操作使用具有一致性。

    二 动机

      绘图编辑器和图形捕捉系统图形应用程序中,总是存在简单的图形到简单的组件再到复杂的组件,

    但他们在本质上都是图形(各种基本的图形组合或者递归组合)。

    这可以分成两个部分:基本图元和组件图形。对于基本的图元可以单独定义类;对于组件图形可以使用图元容器(Container)。

      结果就是:在使用时,对于同样的都是图形的图元和组件必须加以区分对待(图元对象Or容器对象)。对于庞大的图形系统,这无疑是非常复杂的!

      解决方法:Composite模式递归组合,实现系统对图元还是组件都一致性对待。

          

    对于Line或者Rectangle或者Picture都是Graphic,都具有相同的Graphic属性。

    但对于Picture来说它是组合基本图元的方式组成的组件,本身会具有新的特性。

    所以在Graphic图形中存在派生类组件的结构:

        

          

    三 适用性及其结构

    1 表示对象的部-整体层次结构

    2 忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

    3 结构:

          

    Component:为组合中的对象生命接口

          在适当情况下,实现所有类共有的接口的缺省行为

          声明一个接口用于访问和管理Component的子组件

          在递归结构中定义一个接口,用于访问一个父部件。

    Leaf:在组合中表示叶节点对象

    Composite:定义所有子部件的行为,实现与子部件相关的操作。

    Composite实现任意组合方式构建定制新的Component。

    4 性能分析

      Leaf和Composite同为Component,实际上之间是区别,Composite是各个Component的组合,

    需要对各个Component进行维护,Leaf是不需要这些维护的。

    所以这些维护接口是Composite自身提供还是Component提供这些维护的接口,比如:addChild,removeChild等。

      透明性:由基类Component提供所有Composite需要的基本一些接口管理其中的ChildComponent,

    如addChild,removeChild等,这样就Leaf或者Composite具有一致性,而在客户端无需区分Leaf还是Composite。

      安全性:基类只提供Leaf相关的接口,作为Composite需要管理器中的ChildComponent需要自己提供。

    保证Leaf的操作安全性。这样导致Leaf和Composite的不一致性需要区别对待,会造成系统的复杂性。

             这个在应用中我觉得,如果我们大量的操作都是基于Leaf的直接使用,而很少用到Composite,可以采取安全性,

    但是这造成的结果就是:扩展性非常差。但通常在使用中大多数都是基于Composite方式,便于扩展和代码重用,

    所以对ChildComponent的管理是非常重要的。在系统中都可以随处可见透明性的Composite模式,以构建一颗树形的对象模型。

    四 代码实现

    以电脑主板为例,电脑主板包括:CPU,内存,扩展槽,芯片组,时钟发生器,IDE接口和软驱,电源模块,I/O接口……

    选取其中的:CPU,芯片组,I/O接口为例

    1 Equicpment基类

    View Code
    /*----------------------------------------------------------------*/
    /* class Equipment */
    /*----------------------------------------------------------------*/
    class Equipment
    {
    #define EQUIP_MAX_NUM (5)
    public:
    Equipment()
    {
    cout<<" Equipment constructor "<<endl;
    for (int i = 0 ; i < EQUIP_MAX_NUM; i++)
    {
    m_equip[i] = NULL;
    }
    }
    void addChildEquip(Equipment* equip)
    {
    for (int i = 0 ; i < EQUIP_MAX_NUM; i++)
    {
    if(m_equip[i] == NULL)
    {
    m_equip[i] = equip;
    break;
    }
    }
    }
    void removeChildEquip(Equipment* equip)
    {
    for (int i = 0 ; i < EQUIP_MAX_NUM; i++)
    {
    if(m_equip[i] == equip)
    {
    m_equip[i] = NULL;
    break;
    }
    }
    }
    void start()
    {
    for (int i = 0 ; i < EQUIP_MAX_NUM; i++)
    {
    if (m_equip[i] != NULL)
    {
    m_equip[i]->startEquipment();
    }
    }
    }
    virtual void startEquipment()
    {
    cout<<"Equipment startEquipment"<<endl;
    }
    private:
    Equipment* m_equip[EQUIP_MAX_NUM];

    };

    2 Chip基类

    View Code
    /*----------------------------------------------------------------*/
    /* class Chip */
    /*----------------------------------------------------------------*/
    class Chip: public Equipment
    {
    public:
    Chip()
    {
    cout<<" Chip constructor "<<endl;
    }
    virtual void startEquipment()
    {
    cout<<" Chip startEquipment "<<endl;
    }
    };

    3 Cpu部分

    View Code
    //CPU部分
    /*
    ----------------------------------------------------------------*/
    /* class CpuProcessor */
    /*----------------------------------------------------------------*/
    class CpuProcessor: public Chip
    {
    public:
    CpuProcessor()
    {
    cout<<" CpuProcessor constructor "<<endl;
    }
    virtual void startEquipment()
    {
    cout<<" CpuProcessor startEquipment "<<endl;
    }
    };

    /*----------------------------------------------------------------*/
    /* class CpuSocket */
    /*----------------------------------------------------------------*/
    class CpuSocket: public Equipment
    {
    public:
    CpuSocket()
    {
    cout<<" CpuSocket constructor "<<endl;
    }
    virtual void startEquipment()
    {
    cout<<" CpuSocket startEquipment "<<endl;
    }
    };

    /*----------------------------------------------------------------*/
    /* class CpuEquipment */
    /*----------------------------------------------------------------*/
    class CpuEquipment: public Equipment
    {
    public:
    CpuEquipment()
    {
    cout<<" CpuEquipment constructor "<<endl<<endl;
    }
    void addChildCpu()
    {
    cout<<"-------------------addChildCpu-------------------"<<endl;
    cpu = new CpuProcessor();
    slot = new CpuSocket();

    this->addChildEquip(cpu);
    this->addChildEquip(slot);
    }

    virtual void startEquipment()
    {
    this->start();
    cout<<" CpuEquipment startEquipment "<<endl<<endl;
    }
    private:
    CpuProcessor* cpu;
    CpuSocket* slot;
    };

    4 ChipSet部分

    View Code
    //ChipSet芯片组
    /*
    ----------------------------------------------------------------*/
    /* class GraphicsChip */
    /*----------------------------------------------------------------*/
    class GraphicsChip: public Chip
    {
    public:
    GraphicsChip()
    {
    cout<<" GraphicsChip constructor "<<endl;
    }
    virtual void startEquipment()
    {
    cout<<" GraphicsChip startEquipment "<<endl;
    }
    };
    /*----------------------------------------------------------------*/
    /* class SoundChip */
    /*----------------------------------------------------------------*/
    class SoundChip: public Chip
    {
    public:
    SoundChip()
    {
    cout<<" SoundChip constructor "<<endl;
    }
    };
    /*----------------------------------------------------------------*/
    /* class ChipSet */
    /*----------------------------------------------------------------*/
    class ChipSet: public Equipment
    {
    public:
    ChipSet()
    {
    cout<<" ChipSet constructor "<<endl<<endl;
    }
    void addChildChip()
    {
    cout<<"-------------------addChildChip-------------------"<<endl;
    GraphicsChip* gChip = new GraphicsChip();
    SoundChip* sChip = new SoundChip();
    this->addChildEquip(gChip);
    this->addChildEquip(sChip);
    }
    virtual void startEquipment()
    {
    this->start();
    cout<<" ChipSet startEquipment "<<endl<<endl;
    }
    private:

    };

    5 I/O接口部分

    View Code
    //I/O接口
    /*
    ----------------------------------------------------------------*/
    /* class IOEquipment */
    /*----------------------------------------------------------------*/
    class IOEquipment: public Equipment
    {
    public:
    IOEquipment()
    {
    cout<<" IOEquipment constructor "<<endl;
    }
    virtual void startEquipment()
    {
    cout<<" IOEquipment startEquipment "<<endl;
    }
    };
    /*----------------------------------------------------------------*/
    /* class KeyboardIO */
    /*----------------------------------------------------------------*/
    class KeyboardIO: public IOEquipment
    {
    public:
    KeyboardIO()
    {
    cout<<" KeyboardIO constructor "<<endl;
    }
    virtual void startEquipment()
    {
    cout<<" KeyboardIO startEquipment "<<endl;
    }
    };
    /*----------------------------------------------------------------*/
    /* class MouseIO */
    /*----------------------------------------------------------------*/
    class MouseIO: public IOEquipment
    {
    public:
    MouseIO()
    {
    cout<<" MouseIO constructor "<<endl;
    }
    virtual void startEquipment()
    {
    cout<<" MouseIO startEquipment "<<endl;
    }
    };
    /*----------------------------------------------------------------*/
    /* class UsbIO */
    /*----------------------------------------------------------------*/
    class UsbIO: public IOEquipment
    {
    public:
    UsbIO()
    {
    cout<<" UsbIO constructor "<<endl;
    }
    virtual void startEquipment()
    {
    cout<<" UsbIO startEquipment "<<endl;
    }
    };

    /*----------------------------------------------------------------*/
    /* class IOEquipmentSet */
    /*----------------------------------------------------------------*/
    class IOEquipmentSet: public Equipment
    {
    public:
    IOEquipmentSet()
    {
    cout<<" IOEquipmentSet constructor "<<endl<<endl;
    }
    void addChildIO()
    {
    cout<<"-------------------addChildIO-------------------"<<endl;
    KeyboardIO* kIO = new KeyboardIO();
    MouseIO* mIO = new MouseIO();
    UsbIO* uIO = new UsbIO();

    this->addChildEquip(kIO);
    this->addChildEquip(mIO);
    this->addChildEquip(uIO);
    }
    virtual void startEquipment()
    {
    this->start();
    cout<<" IOEquipmentSet startEquipment "<<endl<<endl;
    }
    };

    6 MotherboardEquipment 主板

    View Code
    //主板
    /*
    ----------------------------------------------------------------*/
    /* class IOEquipmentSet */
    /*----------------------------------------------------------------*/
    class MotherboardEquipment: public Equipment
    {
    public:
    MotherboardEquipment()
    {
    cout<<" MotherboardEquipment constructor "<<endl<<endl;
    }
    void addAllChildEquip()
    {
    cout<<"-------------------addAllChildEquip-------------------"<<endl;
    CpuEquipment* cpuEquip = new CpuEquipment();
    cpuEquip->addChildCpu();

    ChipSet* chipEquip = new ChipSet();
    chipEquip->addChildChip();

    IOEquipmentSet* ioEquip = new IOEquipmentSet();
    ioEquip->addChildIO();

    this->addChildEquip(cpuEquip);
    this->addChildEquip(chipEquip);
    this->addChildEquip(ioEquip);
    }
    };

    例子可能并非很完善和合理,仅仅是为了演示一下Composite模式。

    五 实例分析

             将以手机上屏幕显示控件为例。控件涉及到UI显示布局和消息传递处理(按键触屏)

          

          

    在Frame类中通过众多基类指针,将所有的对象组成一个树形结构。有助于对象管理和内存管理。

    如果父类对象释放那么其子对象没有存在的必要了,根据这棵树就能遍历所有子对象,并将其释放掉

    (当然并不是在这里,这里仅包含的是Frame对象的树结构)主要是用于界面显示布局层次和消息传递响应。

  • 相关阅读:
    [CTF]Capture The Flag -- 夺旗赛
    [DesignPattern]Builder设计模式
    [Git]Git 常用的操作命令
    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 示例: 给定 nums = [2, 7, 11, 15], target = 9 因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1]
    QT 实现 读取 增加 删除 实时操作xml
    QT5-图形视图框架
    C++之QT
    ,即双方交锋的次数。随后N行,每行给出一次交锋的信息,即甲、乙双方同时给出的的手势。C代表“锤子”、J代表“剪刀”、B代表“布”,第1个字母代表甲方,第2个代表乙方,中间有1个空格。
    要获得一个C语言程序的运行时间,常用的方法是调用头文件time.h,其中提供了clock()函数,可以捕捉从程序开始运行到clock()被调用时所耗费的时间。这个时间单位是clock tick,即“时钟打点”。同时还有一个常数CLK_TCK,给
    给定N个非0的个位数字,用其中任意2个数字都可以组合成1个2位的数字。要求所有可能组合出来的2位数字的和。例如给定2、5、8,则可以组合出:25、28、52、58、82、85,它们的和为330。
  • 原文地址:https://www.cnblogs.com/bastard/p/2322278.html
Copyright © 2011-2022 走看看