我已经在C ++和Python中创建了一个控制台菜单,但我认为这里的语言不是很重要,因为我在询问类的结构。
所以我想要实现的是一个类似于MS-DOS的菜单,我可以在其中拥有父菜单(文件夹)和操作菜单(文件)。一旦打印出来,这就是它在控制台中的样子:
[-] Root directory
Open snakegame
[-] First sub directory
Print out stupid messages
[+] Closed directory in open directory
Shutdown computer
[+] These directories are closed
[+] You can't see the content inside them
Quit menu
如你所见,我在这里有两种菜单;
Root directory
现已打开,您可以看到其中的所有菜单。如果它关闭,[-]
将变为[+]
,您将看不到任何其他菜单。Open snakegame
可以链接到函数startSnakeGame()
,这将关闭菜单并启动蛇游戏。我已经编写了两个工作实现来获得想要的结果,我只是想知道,我应该使用哪一个?第一种方式是,我只有一个名为Menu
的类,它将所有成员变量和方法编码到一个类中。另一种方式是,我将这两种不同类型的菜单分成两个类,并带有一个共同的基类。
以下是一些成员变量,我现在将它们分成三个部分(基类,目录类和动作类),但它们可以组合成一个类。
基本菜单:
parent
=一个菜单(目录一),将this/self
作为孩子保存在列表/向量中(见下文)。label
=显然是打印菜单时显示的标签。selected
=布尔值,告诉我们当前选择菜单(用鼠标指示)。目录菜单:
subMenus
=一个列表或向量(在C ++中),其中包含其他菜单。open
=一个布尔值,告诉菜单是打开还是关闭。动作菜单:
action
=指向此菜单激活时调用的函数的指针。正如您所看到的,只有少数变量与其他类不同,并且可以设置为如果action == 0
(无操作),则菜单会自动将open
更改为{{ 1}}取决于它的当前值。这种方式操作菜单将被终止,并且只有行动菜单将保留false/true
和subMenus
而不使用。
这可能完全取决于一个人的意见,但我一直在考虑这个问题,并且找不到一种优于其他方式的方法,它们都有自己的优点和缺点,而且两者都运作良好。所以我问你的意见,我很想知道是否有人有任何理由为什么他们选择一个而不是另一个。基本上我是在问原因,我不在乎你的意见。
除了文件夹和文件之外,没有其他菜单类型,因此基类不能用于其他任何内容。
编辑:关于如何使用菜单的简单Python和C ++示例:
只有一个类的Python:
closed
具有多个类的Python:
# Using default param. here to set "action = None" or "action = toggleOpen()"
root = Menu(None, "Root directory")
snake = Menu(root, "Open snakegame", startSnakeGame)
sub1 = Menu(root, "First sub directory")
printMsg = Menu(sub1, "Print out stupid messages")
...
带有一个类的C ++:
# With multiple classes, action parameter no longer exists
root = DirectoryMenu(None, "Root directory")
snake = ActionMenu(root, "Open snakegame", startSnakeGame)
...
具有多个类的C ++:
Menu* root = new Menu(0, "Root directory");
Menu* snake = new Menu(&root, "Open snakegame", &startSnakeGame);
...
第二编辑:我只在Python中实现了两种方式,而在C ++中只实现了一种方式。所以我开始用C ++编写多类方法,只是为了好玩和练习,我遇到了一个问题;有一个基类,我不能将DirectoryMenu* root = new DirectoryMenu(0, "Root directory");
ActionMenu* snake = new ActionMenu(&root, "Open snakegame", &startSnakeGame);
...
添加到父的this
- 向量,因为基类不拥有subMenus
,基类不能知道subMenus
。
所以我将不得不破解我的方式,这是一个很大的减号。除非有人能想出一个好方法来实现它吗?
DirectoryMenu
答案 0 :(得分:2)
第二种方式更为可取(实际上它是http://sourcemaking.com/design_patterns/composite)。实现与界面分离 - 易于添加新的菜单项。此外,此结构适用于模式访问者http://sourcemaking.com/design_patterns/visitor
您可以添加到此代码跟踪并查看输出:
#include <vector>
#include <boost/shared_ptr.hpp>
class ActionMenu;
class SubMenu;
class Menu;
typedef boost::shared_ptr<Menu> MenuPtr;
typedef boost::shared_ptr<SubMenu> SubMenuPtr;
typedef boost::shared_ptr<ActionMenu> ActionMenuPtr;
//visitor
class Action
{
public:
virtual void visit(ActionMenu* actionMenu) = 0;
virtual void visit(SubMenu* subMenu) = 0;
};
//element
class Menu
{
public:
virtual void Accept(Action& action) = 0;
};
//menus
class SubMenu : public Menu
{
public:
virtual ~SubMenu()
{
}
unsigned long GetMenuCount()
{
return m_menus.size();
}
MenuPtr GetMenyByIndex(unsigned long index)
{
return m_menus[index];
}
void AddMenu(const MenuPtr& menu)
{
m_menus.push_back(menu);
}
virtual void Accept(Action& action)
{
action.visit(this);
}
void ShowMenu()
{
}
void ChangeStyle()
{
}
private:
std::vector<MenuPtr> m_menus;
};
class ActionMenu : public Menu
{
public:
virtual ~ActionMenu()
{
}
virtual void Accept(Action& action)
{
action.visit(this);
}
void DoCommand()
{
}
void ChangeImage()
{
}
};
//visitors
class StyleAction : public Action
{
public:
virtual ~StyleAction()
{
}
virtual void visit(ActionMenu* actionMenu)
{
actionMenu->ChangeImage();
}
virtual void visit(SubMenu* subMenu)
{
subMenu->ChangeStyle();
}
};
class MenuAction : public Action
{
public:
virtual ~MenuAction()
{
}
virtual void visit(ActionMenu*actionMenu)
{
actionMenu->DoCommand();
}
virtual void visit(SubMenu* subMenu)
{
subMenu->ShowMenu();
}
};
int main(int argc, char* argv[])
{
SubMenuPtr rootMenu(new SubMenu());
SubMenuPtr fileMenu(new SubMenu());
SubMenuPtr userMenu(new SubMenu());
MenuPtr open(new ActionMenu());
MenuPtr save(new ActionMenu());
MenuPtr close(new ActionMenu());
fileMenu->AddMenu(open);
fileMenu->AddMenu(save);
fileMenu->AddMenu(close);
rootMenu->AddMenu(fileMenu);
rootMenu->AddMenu(userMenu);
StyleAction sa;
MenuAction ma;
//iterate over root menu
//recursively can bypass all the menu items, the structure of the tree
for (unsigned int i = 0; i < rootMenu->GetMenuCount(); ++i)
{
rootMenu->GetMenyByIndex(i)->Accept(sa);
rootMenu->GetMenyByIndex(i)->Accept(ma);
}
return 0;
}
答案 1 :(得分:0)
这两种方式在性能等方面非常接近,所以有点难以弄清楚。
但是,有一个理由选择一个:OOP中的逻辑和规则。我必须将其拆分为3个类:BaseMenu
,ActionMenu
和DirectoryMenu
。
在这里解决“两个班级不能互相认识”的问题可能就像iogane gamba puti fon gu
建议的那样。但是,在addSubMenu()
中定义抽象方法removeSubMenu()
和BaseMenu
对于规则来说就像只有一个类一样,所以这不是一种选择。
我最终得到的是使用回调并重载指针(*
)运算符。它现在返回一个指向另一个类的实例的指针,并根据类型调用它的方法。