设计模式之组合模式

一、模式动机

   类似菜单,里面不仅菜单项,还要包含子菜单。需要实现这种多级菜单 。

二、模式定义

  组合模式(Composite Pattern)允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能 让客户以一致的方式处理个别对象以及对象组合。UML图如下:

这里写图片描述

三、模式示例

  现在对象村餐厅想在菜单里,餐厅菜单里添加甜点菜单。也就是不仅仅要支持多个菜单,甚至还要支持菜单里的菜单。

C++代码实现:

#include <string>
#include <vector>
#include <iostream>

using namespace std;

//父类组件
class MenuComponent
{
public:
    MenuComponent();
    ~MenuComponent();
    virtual string getName() { throw std::exception("ERROR"); }
    virtual string getDescription() { throw std::exception("ERROR"); }
    virtual double getPrice() { throw std::exception("ERROR"); }
    virtual bool isVegetarian() { throw std::exception("ERROR"); }
    virtual void print() { throw std::exception("ERROR"); }
    virtual void add(MenuComponent* component) { throw std::exception("ERROR"); }
    virtual void remove(MenuComponent* component) { throw std::exception("ERROR"); }
    virtual MenuComponent* getChild(int  index) { throw std::exception("ERROR"); }

private:

};

MenuComponent::MenuComponent()
{
}

MenuComponent::~MenuComponent()
{
}


//迭代器基类  
class Iterator
{
public:
    //是否有下一个菜单  
    virtual bool hasNext() = 0;
    //取下一个菜单  
    virtual MenuComponent* next() = 0;
};

class NullIterator :public Iterator
{
public:
    NullIterator();
    ~NullIterator();
    MenuComponent* next()
    {
        return NULL;
    }
    bool hasNext()
    {
        return false;
    }
};

NullIterator::NullIterator()
{

}

NullIterator::~NullIterator()
{

}
//煎饼屋餐单迭代器  
class CompositeIterator : public Iterator
{
public:
    CompositeIterator(vector<MenuComponent*> item)
    {
        items = item;
        iter = items.begin();
    }
    MenuComponent* next()
    {
        MenuComponent* menuItem = *iter;
        ++iter;
        return menuItem;
    }

    bool hasNext()
    {
        if (iter == items.end())
        {
            return false;
        }
        else
        {
            return true;
        }
    }
private:
    vector<MenuComponent*> items;
    vector<MenuComponent*>::const_iterator iter;
};

//菜单项
class MenuItem : public MenuComponent
{
public:
    MenuItem()
    {

    }
    MenuItem(string name, string description, bool vegetarian, double price)
    {
        name_ = name;
        description_ = description;
        vegetarian_ = vegetarian;
        price_ = price;
    }
    ~MenuItem()
    {

    }

    string getName()  { return name_; }
    string getDescription()  { return description_; }
    bool  isVegetarian()  { return vegetarian_; }
    double getPrice()  { return price_; }
    void print()
    {
        cout << getName() << endl;
        cout << getDescription() << endl;
        cout << getPrice() << endl;
    }

    void add(MenuComponent* component)
    {

    }
    void remove(MenuComponent* component)
    {

    }
    MenuComponent* getChild(int index)
    {
        return NULL;
    }

    Iterator* createIterator(){ return new NullIterator; }

private:
    string name_;
    string description_;
    bool vegetarian_;
    double price_;
};


//餐单基类  
class Menu : public MenuComponent
{
public:
    Menu(string name, string description);
    string getName() { return name_; }
    string getDescription() { return description_; }
    MenuComponent* getChild(int index)
    {
        return menu_compents_[index];
    }
    void print()
    {
        cout << getName() << endl;
        cout << getDescription() << endl;
        Iterator* iterator = createIterator();
        while (iterator->hasNext())
        {
            MenuComponent* menuComponet = iterator->next();
            menuComponet->print();
        }

    }
    vector<MenuComponent*> GetMenuItems() { return menu_compents_; }
    Iterator* createIterator(){ return new CompositeIterator(this->GetMenuItems()); }
    void add(MenuComponent* component)
    {
        menu_compents_.push_back(component);
    }

protected:
    vector<MenuComponent*>  menu_compents_;

private:
    string name_;
    string description_;

};

Menu::Menu(string name, string description)
    :name_(name),
    description_(description)
{
}



//煎饼屋菜单
class PancakeHouseMenu :public Menu
{
public:
    PancakeHouseMenu(string name, string description);
    ~PancakeHouseMenu();

    void AddItem(string name, string description, bool vegetarian, double price)
    {
        MenuItem* menuItem = new MenuItem(name, description, vegetarian, price);
        add(menuItem);
    }

private:

};

PancakeHouseMenu::PancakeHouseMenu(string name, string description)
    :Menu(name, description)
{
    AddItem("K&B's Pancake Breakfast", "Pancakes with scrambled eggs, and toast", true, 2.99);
    AddItem("Regular Pancake Breakfast", "Pancakes with fried eggs, sausage", false, 2.99);
    AddItem("Blueberry Pancakes", "Pancakes  made with fresh blueberries", true, 3.49);
    AddItem("Waffles", "with you choice of blueberries or strawberries", true, 3.59);
}

PancakeHouseMenu::~PancakeHouseMenu()
{
}

class DinerMenu :public Menu
{
public:
    DinerMenu(string name, string description);
    ~DinerMenu();

    void AddItem(string name, string description, bool vegetarian, double price)
    {
        MenuItem* menuItem = new MenuItem(name, description, vegetarian, price);
        menu_compents_.push_back(menuItem);
    }

private:

};

DinerMenu::DinerMenu(string name, string description)
    :Menu(name, description)
{
    AddItem("Vegetarian BLT", "(Fakin) Bacon with lettuce & tomato on whole wheat", true, 2.99);
    AddItem("BLT", "Bacon with lettuce & tomato on whole wheat", false, 2.99);
    AddItem("Soup of the day", "Soup of the day, with a side of potato salad", false, 3.29);
    AddItem("Hotdog", "a hot dog, with saurkraut,relish,onions,topped with cheese", false, 3.05);
}

DinerMenu::~DinerMenu()
{
}

class DessertMenu : public Menu
{
public:
    DessertMenu(string name, string description);
    ~DessertMenu();
    void AddItem(string name, string description, bool vegetarian, double price)
    {
        MenuItem* menuItem = new MenuItem(name, description, vegetarian, price);
        menu_compents_.push_back(menuItem);
    }

private:

};

DessertMenu::DessertMenu(string name, string description)
    :Menu(name, description)
{
    AddItem("Apple Pie", "Apple pie with a flakey crust, topped with vanilla ice cream", true, 1.59);
}

DessertMenu::~DessertMenu()
{
}

class Waitess
{
public:
    Waitess(MenuComponent* allMenus);
    ~Waitess();
    void printMenu()
    {
        all_menu_->print();
    }

private:
    MenuComponent* all_menu_;

};

Waitess::Waitess(MenuComponent* allMenus)
    :all_menu_(allMenus)
{
}

Waitess::~Waitess()
{
}


int _tmain(int argc, _TCHAR* argv[])
{

    PancakeHouseMenu* pancakeHouseMenu = new PancakeHouseMenu("PancakeHouseMenu", "PancakeHouseMenu");
    DinerMenu* dinerMenu = new DinerMenu("DinerMenu","DinerMenu");
    DessertMenu* dessertMenu = new DessertMenu("DessertMenu", "DessertMenu");
    dinerMenu->add(dessertMenu);
    MenuComponent* allMenus = new Menu("AllMenus", "AllMenus");
    allMenus->add(pancakeHouseMenu);
    allMenus->add(dinerMenu);
    Waitess waitess(allMenus);
    waitess.printMenu();
    system("pause");
    return 0;
}

运行结果:

这里写图片描述

四、分析总结

  组合模式提供一个结构,可同时包容个别对象和组合对象。组合模式允许客户对个别对象和组合对象一视同仁。组合结构内的任意对象称为组件,组件可以是组合,也可以是叶节点。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值