zoukankan      html  css  js  c++  java
  • 设计模式之实现组合模式

    /******************************************************

    baseobject.h

    ******************************************************/

    #pragma once
    #include <iostream>
    #include <string>
    #include <vector>
    #include "CIterator.h"
    #define MAX_ARRAY_SIZE 100
    using namespace std;

    //前置定义
    class CIteratorInterface;
    class CElectricIterator;

    ///////////////////////////////////////////////
    //******************
    //组合模式的基类,CCompenent。只留接口。把成员留给子类
    //组合有两种,分别是组合本身(递归)及其叶子
    //////////////////////////////////////////////
    class CComponent
    {
    protected:
     //设假设名字是唯一的。这里就不去做ID的唯一了。
     string m_Name;

     bool   m_bIsComponentOrLeaf;
    public:

     //组合类的三个基本方法,只能由非叶子结点来操作
     //在这里例子中就是Menu
     virtual void addComponent(CComponent* menuComponent) {
      //这里可以直接抛出一个说明这个操作不被允许的异常
      return;  
     }

     virtual void removeComponent(CComponent* rmComponent) {
      return;
     }

     virtual CComponent* getChild(unsigned long  i) {
      return NULL;
     }

     //其它菜单项与菜单共有的方法
     virtual string getName()
     {
      return m_Name;
     }

     //统一叶节点与非叶节点的print方法
     //这样就可以用先序遍历的方法来迭代叶子节点和非叶子节点了。
     virtual void PrintInformation() = 0;

     inline void setComponent(){
      m_bIsComponentOrLeaf = true;
     }

     inline bool isComponent(){
      return m_bIsComponentOrLeaf;
     }

     CComponent(string inName) : m_Name(inName),m_bIsComponentOrLeaf(false){}

     virtual ~CComponent() {}
    };

    //////////////////////////////////////////
    //在C++对象不像在Java中一样,有统一的基类Ojbect,
    //所以,我们在这里为所有要出售的对象设定一个对象的基类
    //重构修改: 这个是做为组合的新叶子结点
    class CBaseObjectMenuItem : public CComponent
    {
    private:
     float  m_Price;
    public:
     CBaseObjectMenuItem(string name, float price) : CComponent(name),  m_Price(price){}

     virtual float getPrice() {
      return m_Price;
     }
     
     virtual string getName(){
      return m_Name;
     }

     //这个已经没用了,可以注销掉
     /*
     void showInformation(){
      cout<<"Name : "<<m_Name<<"\t\t\t";
      cout<<"Price : "<<m_Price<<endl;
     }
     */

     void PrintInformation(){
      cout<<"Name : "<<m_Name<<"\t\t\t";
      cout<<"Price : "<<m_Price<<endl;
     }
    public:

    };

    ////////////////////////////////////////////
    //我这里先给出一个菜单类的接口,
    //这里简单处理菜单项,假设菜单项总是由一个名字和一个价格所决定的
    //重构修改: 这个是做为组合的新组合类
    //这里其实是一个递归式
    class CSaleMenu : public CComponent
    {
    public:
     virtual CIteratorInterface* createIterator() = 0;

    public:
     CSaleMenu(string inName) : CComponent(inName) {}

     //组合类的三个基本方法,只能由非叶子结点来操作
     //在这里例子中就是Menu

     void addComponent(CComponent* menuComponent) = 0;

     void removeComponent(CComponent* rmComponent) {
            //我在这里就不实现这个了,谁看这个程序的话,就帮我补充上去了吧
     }

     CComponent* getChild(unsigned long  i);

     virtual ~CSaleMenu(){ }

    public:
     //显示菜单
     //先序遍历菜单
     void PrintInformation();
    };

    /////////////////////////////////////////
    //电器菜单类,用数组实现
    //其中有一个方法可以用来创建一个迭代器
    class CElectricMenu : public CSaleMenu
    {
    private:
     unsigned long       m_totalItems;

     //我这里也用指针的原因是为了防止对象切片(slicing)
     //因为现在这里还是非常简单的情况就是,菜单对像还只是一个基类的直接对象
     //如果这个对象是一个菜单项基类的派生类的对象时,切记:千万不要以数组的多态方式来处理
     //这样会导致切片问题,可详见more efficient C++的相关章节
     CComponent* m_ItemPointers[MAX_ARRAY_SIZE];

    public:
     //组合方法重载
     void addComponent(CComponent* menuComponent){
      if(!menuComponent)
       return;
            m_ItemPointers[m_totalItems++] = menuComponent;
     }

    public:
     CElectricMenu(string inName) : CSaleMenu(inName), m_totalItems(0){}

     inline unsigned long getTotalMenuItems(){
      return m_totalItems;
     }

     CComponent** getMenu(){
      return m_ItemPointers;
     }

     CIteratorInterface* createIterator();


     ~CElectricMenu(){
      for(unsigned long i = 0; i < m_totalItems; i++)
       delete m_ItemPointers[i];
     }
    };

    /////////////////////////////////////////
    //食品菜单菜,用vector实现
    class CFoodMenu : public CSaleMenu
    {
    private:
     //我这里也用指针的原因是为了防止对象切片(slicing)
     //因为现在这里还是非常简单的情况就是,菜单对像还只是一个基类的直接对象
     //如果这个对象是一个菜单项基类的派生类的对象时,切记:千万不要以数组的多态方式来处理
     //这样会导致切片问题,可详见more efficient C++的相关章节

     //这里把CBaseObjectMenuItem改为CComponent
     vector<CComponent*> m_ItemPointer;
    public:
     CFoodMenu(string inName) : CSaleMenu(inName){}

     //组合方法重载
     void addComponent(CComponent* menuComponent){
      if(!menuComponent)
       return;
      m_ItemPointer.push_back(menuComponent);
     }

     vector<CComponent*>& getMenu(){
      return m_ItemPointer;
     }

     CIteratorInterface* createIterator();

     ~CFoodMenu(){
      for(int i = 0; i < static_cast<int>(m_ItemPointer.size()); i++){
       delete m_ItemPointer[i];
      }
      m_ItemPointer.clear();
     }
    };

    /**********************************************************

    CIterator.h

    **********************************************************/

    #pragma once
    #include <iostream>
    #include <string>
    #include <vector>
    #include "baseobject.h"
    using namespace std;

    class CBaseObjectMenuItem;
    class CComponent;

    //在原有的基础上,把这里所有MenuItem的基类改为CComponent

    //////////////////////////////////////////
    //迭代器的接口,这是每个迭代器都要实现的.
    class CIteratorInterface
    {
    public:
     virtual bool hasNext() = 0;
     virtual CComponent* next() = 0;
    };

    /////////////////////////////////////////
    //这是一个用于数组接口的迭代器,我们实现了电器数组的迭代
    //用数据实现
    class CElectricIterator : public CIteratorInterface
    {
    private:
     unsigned long m_totalItems;
     CComponent** m_MenuItem;

     unsigned long m_currentIt;

    public:
     CElectricIterator(CComponent** inMenu, unsigned long inTI);

     bool hasNext();

     CComponent* next();
    };

    /////////////////////////////////////////
    //这是一个用于vector接口的迭代器,我们实现了食物vector的迭代
    //用vector实现
    class CFoodIterator : public CIteratorInterface
    {
    private:
     vector<CComponent*>& m_MenuItem;

     unsigned long m_currentIt;
    public:
     CFoodIterator(vector<CComponent*>& inItemList);

     bool hasNext();

     CComponent* next();
    };

    /********************************************************

    CMenuShower.h

    ********************************************************/

    #pragma once
    #include <iostream>
    #include "../组合模式/baseobject.h"
    #pragma once
    #include "../组合模式/CIterator.h"
    #include "../组合模式/baseobject.h"


    //////////////////////////////////////////////
    //这个客户类就和原先完全不一样了
    //现在这个客户类有唯一的一个component
    class CMenuShower2
    {
    private:
     CComponent* m_component;
    public:
     CMenuShower2(CComponent* rootComponent) :
       m_component(rootComponent)
       {

       }

        void PrintMenu()
     {
      m_component->PrintInformation();
     }
     
    };

    /*********************************************************

    baseobject.cpp

    *********************************************************/

    #include "baseobject.h"

    #include "CIterator.h"


    CIteratorInterface* CElectricMenu::createIterator()
    {
     //注意这里new了一个iterator
     //在调用的地方,调用完了之后,一定要把这块内存释放掉。
     return static_cast<CIteratorInterface*>(
      new CElectricIterator(m_ItemPointers, m_totalItems));
    }


    CIteratorInterface* CFoodMenu::createIterator()
    {
     //注意这里new了一个iterator
     //在调用的地方,调用完了之后,一定要把这块内存释放掉。
     return static_cast<CIteratorInterface*>(
      new CFoodIterator(m_ItemPointer));
    }


    void CSaleMenu::PrintInformation()
    {
     //这里我在组合模式中,嵌套了迭代器模式
     CIteratorInterface* it = createIterator();
     while(it->hasNext())
     {
      CComponent*bmi = (CComponent*)it->next();
      if(bmi)
       bmi->PrintInformation();
     }

     delete it;
    }

    CComponent* CSaleMenu::getChild(unsigned long i)
    {
     unsigned long tpidx = 0;
     CIteratorInterface* it = createIterator();
     while(it->hasNext())
     {
      if(tpidx++ == i)
       return static_cast<CComponent*>(it->next());
     }
     delete it;
     return NULL;
    }

    /***********************************************************

    Citerator.cpp

    ***********************************************************/

    #include "CIterator.h"
    #include "baseobject.h"

    /////////////////////////////////////////
    //这是一个用于数组接口的迭代器,我们实现了电器数组的迭代
    //用数据实现
    //实现部分
    CElectricIterator::CElectricIterator(CComponent** inMenu, unsigned long inTI)
    : m_MenuItem(inMenu), m_totalItems(inTI), m_currentIt(0){

    }

    bool CElectricIterator::hasNext()
    {
     return m_currentIt < m_totalItems ? true : false;
    }

    CComponent* CElectricIterator::next(){
     if(m_currentIt < m_totalItems)
      return m_MenuItem[m_currentIt++];
     return NULL;
    }


    /////////////////////////////////////////
    //这是一个用于vector接口的迭代器,我们实现了食物vector的迭代
    //用vector实现
    //实现部分
    CFoodIterator::CFoodIterator(vector<CComponent*>& inItemList)
    : m_MenuItem(inItemList), m_currentIt(0){

    }

    bool CFoodIterator::hasNext()
    {
     return m_currentIt < m_MenuItem.size() ? true : false;
    }

    CComponent* CFoodIterator::next(){
     if(m_currentIt < m_MenuItem.size())
      return m_MenuItem[m_currentIt++];
     return NULL;
    }

    /***********************************************************

    testCompositionPattern.cpp

    ***********************************************************/

    /*
       设计模式; 组合模式

       允许我们将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。
       组合模式让我们能用树形方式创建对象的结构,树里面包含了组合以及个别的对象。(比如说,实现子菜单。)
       使用组合结构,我们能把相同的操作应用在组合和个别对象上。换句话说,在大多数情况下,我们可以忽略对象组合和个别对象之间的差别。
       组件与组合:
       组合包含组件。组件有两种:组合与叶节点元素。(递归?不是吗。)。组合持有一群孩子,这些孩子可以是别的组合或者叶节点元素。
       当我们用这种方式组织数据的时候,最终会得到树形结构。
       类结构说明:客户拥有一个Component来操作组合中的对象。
       Component为组合为的所有对象定义一个接口,不管是组合还是叶节点(Component可以为add(),remove(), getchild()和它的操作实现一些默认的行为)。
       叶节点没有孩子,它通过实现Composite支持的操作,定义了组合内的元素的行为。Composite的角色是要定义组件的行为,而这样的组件具有子节点。(见类图)

    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    这个程序要做的是:
        对迭代器模式的那个程序进行重构,从而实现子菜单的功能。
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

       by 何戬, hejian@cad.zju.edu.cn
    */
    #include <iostream>
    #include "../组合模式/CMenuShower.h"
    using namespace std;

    int main()
    {
     //根菜单
     CComponent* rootComponent = new CElectricMenu("电器菜单");

     CMenuShower2* menuShower = new CMenuShower2(rootComponent);

     //根菜单下有一个手机的子菜单
     CSaleMenu* cellphone = new CElectricMenu("电器菜单-手机");
     rootComponent->addComponent(cellphone);

     //手机菜单下有两款手机
     cellphone->addComponent(new CBaseObjectMenuItem("电器菜单-手机-诺基亚E71", 2300.0f));
     cellphone->addComponent(new CBaseObjectMenuItem("电器菜单-手机-诺基亚N79", 2120.0f));

     CSaleMenu* cellphoneApple = new CElectricMenu("电器菜单-手机");
     cellphoneApple->addComponent(new CBaseObjectMenuItem("电器菜单-手机-iPhone 3G", 4650.0f));
     cellphoneApple->addComponent(new CBaseObjectMenuItem("电器菜单-手机-iPhone 8G", 2100.0f));

     //再加一个子菜单
     cellphone->addComponent(cellphoneApple);

     //////////////////////////
     //现在我要在诺基亚E71下,细分成

     ////////////////////////////
     //加点零食主菜单
     CSaleMenu* fmenu = new CFoodMenu("零食菜单");

     CSaleMenu* fKFC = new CFoodMenu("KFC");
     fKFC->addComponent(new CBaseObjectMenuItem("KFC 1号套餐", 23.5f));
     fKFC->addComponent(new CBaseObjectMenuItem("KFC 2号套餐", 19.5f));
     fKFC->addComponent(new CBaseObjectMenuItem("KFC 3号套餐", 25.5f));

     rootComponent->addComponent(fmenu);
     //在我的这个程序里像以下这样做是不允许的.
     //一个菜单被加入到任何地方两次或以上
     //因为这样会导致同一个对象会被析构两次.
     //rootComponent->addComponent(fmenu)
     fmenu->addComponent(new CBaseObjectMenuItem("浙江大学靓园早饭", 2.5f));

     fmenu->addComponent(fKFC);


     //现在MC也来了//价格一样,东西不一样.
     CSaleMenu* fMcDn = new CFoodMenu("McD");
     fKFC->addComponent(new CBaseObjectMenuItem("Mc 1号套餐", 23.5f));
     fKFC->addComponent(new CBaseObjectMenuItem("Mc 2号套餐", 19.5f));
     fKFC->addComponent(new CBaseObjectMenuItem("Mc 3号套餐", 25.5f));

     fmenu->addComponent(fMcDn);


     //////////////////////////////////////
     //现在又有索爱的手机来了.
     CSaleMenu* saPhone = new CElectricMenu("电器菜单-手机-索爱");
     saPhone->addComponent(new CBaseObjectMenuItem("电器菜单-手机-索爱p900i", 1600.0f));
     saPhone->addComponent(new CBaseObjectMenuItem("电器菜单-手机-索爱p660i", 800.0f));
     saPhone->addComponent(new CBaseObjectMenuItem("电器菜单-手机-索爱K900c", 1200.0f));

     cellphone->addComponent(saPhone);

     menuShower->PrintMenu();
     delete menuShower;
     delete rootComponent;
     return 0;
    }

  • 相关阅读:
    利用dockerfile定制镜像
    发布Docker 镜像到dockerhub
    Docker 停止容器
    133. Clone Graph
    132. Palindrome Partitioning II
    131. Palindrome Partitioning
    130. Surrounded Regions
    129. Sum Root to Leaf Numbers
    128. Longest Consecutive Sequence
    127. Word Ladder
  • 原文地址:https://www.cnblogs.com/skyofbitbit/p/2756482.html
Copyright © 2011-2022 走看看