基于C++的《Head First设计模式》笔记——组合模式

目录

一.专栏简介

二.背景

三.定义组合模式

四.用组合设计和实现菜单

五.总结


一.专栏简介

本专栏是我学习《head first》设计模式的笔记。这本书中是用Java语言为基础的,我将用C++语言重写一遍,并且详细讲述其中的设计模式,涉及是什么,为什么,怎么做,自己的心得等等。希望阅读者在读完我的这个专题后,也能在开发中灵活且正确的使用,或者在面对面试官时,能够自信地说自己熟悉常用设计模式。

本章将开始组合模式的学习,是上一篇迭代器模式的后传。

二.背景

书接上回,对象村打算在Diner Menu菜单中添加一个子菜单,我们同样需要支持客户方便地遍历所有菜单。我们就需要用到组合模式。

三.定义组合模式

组合模式允许我们将对象组合成树形结构来表现部分-整体层次结构。组合让客户可以统一处理个别对象和对象组合。

这个模式让我们创建树形结构,嵌套的菜单和菜单项组可以用同一结构来处理。通过把菜单和菜单项放进同一结构,我们创建了一个部分-整体层次,即一棵对象树,它由部件(菜单和菜单项)组成,却可以当成一个整体对待。

类图如下:

四.用组合设计和实现菜单

因此,我们如何把组合模式应用到我们的菜单?一开始,我们需要创建一个组件接口,该接口作为菜单和菜单项的通用接口,允许我们统一地对待它们。换句话说,我们可以在菜单或菜单项中调用同样的方法。

现在,调用菜单或菜单项上的某些方法可能没有意义,但我们可以处理,只需等一会。目前,我们快速浏览一下菜单如何符合组合模式结构:

下面,我们用代码实现,代码如下:

Composite.h:

cpp 复制代码
#pragma once

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class MenuComponent
{
public:
	virtual void add(MenuComponent* menuComponent) { cerr << "Menu can not add" << endl; }
	virtual void remove(MenuComponent* menuComponent) { cerr << "Menu can not remove" << endl; }
	virtual MenuComponent* getChild(int i) { cerr << "Menu can not getChild" << endl; return nullptr; }
	virtual const string& getName() const { cerr << "MenuItem can not getName" << endl; return nullStr; }
	virtual const string& getDescription() const { cerr << "MenuItem can not getDescription" << endl; return nullStr; }
	virtual const double getPrice() const { cerr << "MenuItem can not getPrice" << endl; return -1; }
	virtual bool isVegeTarian() const { cerr << "MenuItem can not isVegeTarian" << endl; return false; }
	virtual void print() const = 0 {}
	bool operator==(const MenuComponent* another) { return this == another; }
private:
	string nullStr;
};

class MenuItem : public MenuComponent
{
public:
	MenuItem(const string& name, const string& description, bool vegetarian, double price):
		_name(name), _description(description), _vegetarian(vegetarian), _price(price)
	{}
	const string& getName() const override { return _name; }
	const string& getDescription() const override { return _description; }
	bool isVegeTarian() const override { return _vegetarian; }
	const double getPrice() const override { return _price; }
	void print() const override
	{
		cout << "菜单项:" << _name;
		if (_vegetarian) cout << "(v)";
		cout << ", " << _price << "      --" << _description << endl;
	}
private:
	string _name;
	string _description;
	bool _vegetarian;
	double _price;
};

class Menu : public MenuComponent
{
public:
	Menu(const string& name, const string& description):
		_name(name), _description(description)
	{}
	void add(MenuComponent* menuComponent) override { menuComponents.push_back(menuComponent); }
	void remove(MenuComponent* menuComponent) override
	{ 
		auto it = menuComponents.begin();
		while (it != menuComponents.end())
		{
			if (*it == menuComponent)
			{
				menuComponents.erase(it);
				return;
			}
			it++;
		}
	}
	MenuComponent* getChild(int i) override { return menuComponents[i]; }
	const string& getName() const override { return _name; }
	const string& getDescription() const override { return _description; }
	void print() const override
	{ 
		cout << endl << _name << ", " << _description << endl << "-------------------" << endl; 

		for (const auto& e : menuComponents)
		{
			e->print();
		}
	}
private:
	vector<MenuComponent*> menuComponents;
	string _name;
	string _description;
};

class Waitress
{
public:
	Waitress(MenuComponent* menuComponent):
		allMenus(menuComponent)
	{

	}
	void printMenu()
	{
		allMenus->print();
	}
private:
	MenuComponent* allMenus;
};

main.cpp:

cpp 复制代码
#include "Composite.h"

int main()
{
	MenuComponent* pancakeHouseMenu = new Menu("PANCAKE HOUSE MENU", "BREAKFAST");
	MenuComponent* dinerMenu = new Menu("DINER MENU", "Lunch");
	MenuComponent* cafeMenu = new Menu("CAFE MENU", "Dinner");
	MenuComponent* dessertMenu = new Menu("DESSERT MENU", "Dessert of course!");

	MenuComponent* allMenu = new Menu("ALL MENUS", "All menus combined");

	allMenu->add(pancakeHouseMenu);
	allMenu->add(dinerMenu);
	allMenu->add(cafeMenu);

	dinerMenu->add(new MenuItem("Pasta", "香啊啊啊啊啊啊", true, 3.89));
	dinerMenu->add(dessertMenu);
	dinerMenu->add(new MenuItem("Apple Pie", "香哈哈哈哈哈哈", true, 1.39));

	cafeMenu->add(new MenuItem("抹茶拿铁", "咖咖咖", false, 20));

	dessertMenu->add(new MenuItem("哈根达斯", "甜甜甜", false, 100));

	Waitress waitress(allMenu);
	waitress.printMenu();

	return 0;
}

运行结果:

五.总结

  • 组合模式允许客户统一地处理组合和个别对象。
  • 组合结构内的任意对象称为组件。组件可以是其他组合或者叶子。
  • 实现组合模式有许多设计上的折中。你要根据需要平衡透明和安全。
相关推荐
计算机安禾13 小时前
【c++面向对象编程】第41篇:函数模板与类模板:泛型编程的基石
开发语言·c++·算法
郝学胜-神的一滴13 小时前
Qt 高级开发 010: 从跨界面传值到自定义信号
开发语言·c++·qt·程序人生·用户界面
天若有情67313 小时前
自研极简C++软交互事件系统:干掉观察者模式、碾压前端事件机制
c++·观察者模式·交互·事件
ZhiqianXia14 小时前
流畅的Python笔记
笔记·python
玄米乌龙茶12314 小时前
LLM成长笔记(四):大语言模型(LLM)基础认知
人工智能·笔记·语言模型
basketball61614 小时前
C++ 继承完全指南:从 is-a 关系到虚继承的底层真相
开发语言·c++
问心无愧051314 小时前
ctf show web入门157
笔记
IOT-Power14 小时前
C++ 工厂模式
c++
Huangjin007_14 小时前
【C++ STL篇(十)】深入理解 AVL 树:代码实现、旋转图解与平衡因子详解
开发语言·c++
奋斗的小乌龟14 小时前
langchain4j笔记-智能体系统01
java·笔记