例如,我可以有类似的东西,
A
B
ba
bb
C
Ca
D
现在我有一个2D数组,但这不是很一般,因为如果我想将最大子级从2扩展到3,我需要另一个维度。任何建议?
答案 0 :(得分:6)
复合模式在这里是一个合适的应用程序:
(来自维基百科:) http://en.wikipedia.org/wiki/Composite_pattern
在你的情况下:
通过对每个SubMenu对象实施一个计数器,您可以根据插入顺序将菜单元素的所需顺序排列到复合“SubMenu”中:每次调用aSubMenu.add(newMenuItemOrSubMenu)
时,aSubMenu
都应增加自己的使用订购号计数并标记新项目。 (实现的具体细节取决于您,您根本不必使用单独的计数器,只需使用列表或数组)
答案 1 :(得分:2)
也许这就是:
class MenuNode
{
public:
MenuNode(std::string new_label);
void Add(MenuNode * new_node);
private:
std::string label;
std::vector<MenuNode *> children; // changed to vector to preserve order
};
用法:
MenuNode menu("root"),
file("File"),
edit("Edit"),
open("Open..."),
close("Close"),
save("Save..."),
prefs("Preferences"),
yes_foo("Activate Foo"),
no_foo("Deactivate Foo");
menu.Add(&file);
menu.Add(&edit);
file.Add(&open);
file.Add(&close);
file.Add(&save);
edit.Add(&prefs);
prefs.Add(&yes_foo);
prefs.Add(&no_foo);
代表:
Main Menu
File
Open...
Close
Save...
Edit
Preferences
Activate Foo
Deactivate Foo
请注意这个例子的明显缺陷,即依赖于(可能)临时变量的地址。您将无法在函数中创建它并将其返回。
实现的部分缺失也是如此,例如,无法遍历示例代码中节点的私有状态。
答案 2 :(得分:2)
sampson-chen提到的复合设计模式是我为小型开发人员监视器实现的正确方法,让您从菜单结构中选择一些测试方法。
我有一个基类“菜单项”,我从中导出子菜单和叶子(菜单项)。叶子只执行某些操作,而子菜单则打开另一个菜单级别。
例如,基类可能与此类似(当您想使用shared_pointers时):
/*************************************************************//*!
* @brief The base class for all menu entry types (sub menus and sub menu entries/items)
******************************************************************/
class MenuEntry : public boost::enable_shared_from_this<MenuEntry>
{
public:
virtual ~MenuEntry(){}
/**************************************************************//*!
* @brief Default implementation to add menu entries; has to be re implemented
* @param[in] newSubMenuEntry - the new menu entry (another sub menu or leaf)
**************************************************************/
virtual void add(boost::shared_ptr<MenuEntry> newSubMenuEntry)=0;
/*****************************************************************//*!
* @brief Default implementation for call to menu entries; always returns false
* @return false - the function has not been re implemented
****************************************************************/
virtual bool call(void)
{
// the member function has not been re-implemented
return false;
}
/*****************************************************************************//*!
* @brief Default implementation, has to be reimplemented
* @return emptyVector - an empty vector
*********************************************************************************/
virtual std::vector<boost::shared_ptr<MenuEntry> > getChildren(void)
{
std::vector<boost::shared_ptr<MenuEntry> > emptyVector;
return emptyVector;
}
/*******************************************************************************//*!
* @brief Gives a pointer to the parent of the actual menu entry
* @return m_parent - pointer to the parent
******************************************************************************/
boost::shared_ptr<MenuEntry> parent(void)
{
return m_parent;
}
/***************************************************************************//*!
* @brief Default implementation for selecting a menu entry
* @param[in] desiredMenuEntry - the desired menu entry which shall be selected
* @return notExisting - a pointer to <b>this</b>
**********************************************************************************/
virtual boost::shared_ptr<MenuEntry> select(boost::shared_ptr<MenuEntry> desiredMenuEntry)=0;
/**************************************************************************//*!
* <B>Criticality: C0 \n\n</B>
* @brief Sets a pointer to the parent of new menu entry
* @param[in] pointerToParent - pointer to the parent
****************************************************************************/
void setParent(boost::shared_ptr<MenuEntry> pointerToParent)
{
m_parent = pointerToParent;
}
/***************************************************************************//*!
* @brief Default implementation for destroying children
*****************************************************************************/
virtual void destroy(void)=0;
protected:
/************************************************************************//*!
* @brief Constructor for a menu entry (sub menu or leaf)
* @param[in] menuEntryName - the name for the sub menu or leaf
*************************************************************************/
MenuEntry(std::string menuEntryName)
{
m_menuEntryName = menuEntryName;
}
};
在select方法中,我检查返回值,如果我有一个执行某事的叶子,或者子菜单,我必须更改我的指针。
为方便起见,您可以添加方法,在子菜单中查找所有子菜单条目以进行显示,或者使用实际菜单路径等构建标题行的方法......另一个想法是扫描方法您的菜单树,以避免双菜单条目asf。
答案 3 :(得分:1)
使用树。无论如何,这最好在树中定义。
其中:rootNode已连接到A
,B
,C
,D
。 B
已与ba
和bb
相关联。 C
已与Ca
相关联。等。
答案 4 :(得分:0)
我在我的Github
ConsoleMenu.h
typedef int (*MENU_FUNCTION_POINTER)();
typedef struct _MENU MENU;
typedef MENU* MENU_POINTER;
struct _MENU
{
bool isValid; // C++ can not compare struct is NULL
string text;
MENU_FUNCTION_POINTER func;
bool isOpen;
MENU_POINTER childMenu;
MENU_POINTER parent;
};
class ConsoleMenu
{
private:
static MENU _chapters[];
static MENU _chapter1[];
static MENU _chapter2[];
};
ConsoleMenu.cpp
MENU ConsoleMenu::_chapters[] = {
{true, "Chapter 1", NULL, false, ConsoleMenu::_chapter1, NULL},
{true, "Chapter 2", NULL, false, ConsoleMenu::_chapter2, NULL},
{true, "Chapter 3", NULL, false, NULL, NULL},
{true, "Chapter 4", NULL, false, NULL, NULL},
{false, "unused", NULL, false, NULL, NULL}
};
MENU ConsoleMenu::_chapter1[] = {
{true, "Example 1.1", Example1, false, NULL, ConsoleMenu::_chapters},
{true, "Example 1.2", Example2, false, NULL, ConsoleMenu::_chapters},
{false, "unused", NULL, false, NULL, NULL}
};
MENU ConsoleMenu::_chapter2[] = {
{true, "Example 2.1", NULL, false, NULL, ConsoleMenu::_chapters},
{true, "Example 2.2", NULL, false, NULL, ConsoleMenu::_chapters},
{true, "Example 2.3", NULL, false, NULL, ConsoleMenu::_chapters},
{false, "unused", NULL, false, NULL, NULL}
};