设计模式之实现---组合模式

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

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

posted on 2012-11-06 10:30  bitbit  阅读(458)  评论(0编辑  收藏  举报