• 设计模式之实现迭代器模式


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

    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;

    //////////////////////////////////////////
    //在C++对象不像在Java中一样,有统一的基类Ojbect,
    //所以,我们在这里为所有要出售的对象设定一个对象的基类
    class CBaseObjectMenuItem
    {
    private:
     string m_Name;
     float  m_Price;
    public:
     CBaseObjectMenuItem(string name, float price) : m_Name(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;
     }
    };

    ////////////////////////////////////////////
    //我这里先给出一个菜单类的接口,
    //这里简单处理菜单项,假设菜单项总是由一个名字和一个价格所决定的
    class CSaleMenu
    {
    public:
     virtual void addMenuItem(string Name, float Price) = 0;

     virtual CIteratorInterface* createIterator() = 0;
    };

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

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

    public:
     CElectricMenu() : m_totalItems(0){}

     void addMenuItem(string Name, float Price){
      m_ItemPointers[m_totalItems++] = new CBaseObjectMenuItem(Name, Price);
     }

     inline unsigned long getTotalMenuItems(){
      return m_totalItems;
     }

     CBaseObjectMenuItem** 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++的相关章节
     vector<CBaseObjectMenuItem*> m_ItemPointer;
    public:
     void addMenuItem(string Name, float Price){
      m_ItemPointer.push_back(new CBaseObjectMenuItem(Name, Price));
     }

     vector<CBaseObjectMenuItem*>& 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 CIteratorInterface
    {
    public:
     virtual bool hasNext() = 0;
     virtual CBaseObjectMenuItem* next() = 0;

     virtual ~CIteratorInterface() {}
    };


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

     unsigned long m_currentIt;

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

     bool hasNext();

     CBaseObjectMenuItem* next();
    };

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

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

     bool hasNext();

     CBaseObjectMenuItem* next();
    };

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

    CMenuShower.h

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

    #pragma once
    #include <iostream>
    #include "baseobject.h"
    #include "CIterator.h"


    //////////////////////////////////////////////
    //是时候来做一个显然菜单的类的
    //这个类是与具体菜单元素存放方式无关的(已经解耦了)
    //当要具体类时,就创建一个iterator,切记,用完后要删除
    class CMenuShower
    {
    private:
     CSaleMenu* m_Menu1; //电子产品类的menu
     CSaleMenu* m_Menu2; //食品类的menu

     //可以像下面这样来管理所有菜单项
     //vector<CSaleMenu*> m_Menus;

    public:
     CMenuShower(CSaleMenu* inElecMenu, CSaleMenu* inFoodMenu) :
     m_Menu1(inElecMenu), m_Menu2(inFoodMenu)
     {

     }

    private:
     static void PrintSingleIterator(CIteratorInterface* it){
      if(!it)
       return;
      while(it->hasNext()){
       CBaseObjectMenuItem* tmp = it->next();
       tmp->showInformation();
      }
     }

    public:

     //哈哈。这下总算是成功与菜单实现解耦了。
     //如果没有解耦的话,我们还需要知道不同人实现的放在数据的方法,然后分别处理。
     //在使用了迭代器模式后,我们就需要知道迭代器模式的接品即可。
     void PrintAllMenuItems(){
      //电器类商品, “电器类菜单说: 你打印吧,不要管我是怎么实现的”
      cout<<"[电器类商品]"<<endl;
      PrintSingleMenu(m_Menu1);

      //食物类商品 “食物类菜单说: 你打印吧,你也不要管我是怎么实现的”
      cout<<"[食物类商品]"<<endl;
      PrintSingleMenu(m_Menu2);
     }

    public:
     static void PrintSingleMenu(CSaleMenu* menu)
     {
      if(!menu)
       return;
      CIteratorInterface* it = menu->createIterator();
      PrintSingleIterator(it);
      delete it;
     }
    };

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

    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));
    }

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

    Citerator.cpp

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

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

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

    }

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

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


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

    }

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

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

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

    testiteratorPattern.cpp

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

    /*
     设计模式: 迭代器模式

     提供一种方法顺序访问一个聚合对象的各个元素 
     首先,迭代器这个方法根本不管聚合究竟是由数组还是由Array或者Vector来保存的.
     其次,迭代器模式把在元素之间遍历的责任交给迭代器,而不是某种特殊的聚合对象.

    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    这个程序运用迭代器模式来遍历一些菜单项
    在程序里有两个菜单项,
      一个是电子产品的菜单项  用数据实现
       一个是食品的菜单项      用vector实现

    现在有一个终端机,并不知道两个菜单项的内在数据的具体存储和实现方式,但需要给客户显现数据的内容.
    所以,我在这里使用了迭代器模式,把迭代过程进行封装.

    CIterator为迭代器的基类

    在这个迭代器模式的例子中Menu子类的createIterator()是这个模式的精髓。
    这个成员返回一个所有封装的迭代器的基类接口.所以使用者就不必要去关心返回的
    迭代器的内部数据存储方式
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

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

    int main()
    {
     CElectricMenu* elecMenu = new CElectricMenu();
     elecMenu->addMenuItem("诺基亚E71", 2300.0f);
     elecMenu->addMenuItem("诺基亚N29", 2120.0f);
     CFoodMenu*     foodMenu = new CFoodMenu;
     foodMenu->addMenuItem("KFC全家套餐", 66.0f);
     foodMenu->addMenuItem("原味吮指鸡块", 7.5f);

     CMenuShower* ms = new CMenuShower(elecMenu, foodMenu);
     ms->PrintAllMenuItems();

     delete foodMenu;
     delete elecMenu;

     return 0;
    }

  • 相关阅读:
    CSS盒子模式(DIV布局快速入门)
    CSS中的滑动门技术
    由浅入深漫谈margin属性
    zz Apache 虚拟主机 VirtualHost 配置
    动态生成编译运行java类
    ubuntu 手动设置DNS服务器,重启后不能上网
    ubuntu下部署发布环境
    zz [Java]读取文件方法大全
    Ubuntu apache2 主机配置文件
    JAVA的CALLBACK
  • 原文地址:https://www.cnblogs.com/skyofbitbit/p/2756566.html
Copyright © 2020-2023  润新知