gpt4 book ai didi

c++ - 重构建议 : How to avoid type checking in this OO design

转载 作者:太空狗 更新时间:2023-10-29 20:06:39 25 4
gpt4 key购买 nike

我正在寻找有关重构的建议,以改进我的类设计并避免类型检查。

我正在使用命令设计模式构建菜单树。菜单中的项目可以有多种类型(例如,即时操作 [如“保存”]、切换开/关属性,根据其状态显示复选/图标 [如“斜体”],等等)。至关重要的是,还有子菜单,它们替换(而不是显示在旁边)屏幕上的当前菜单。这些子菜单当然包含它们自己的菜单项列表,可以有更多的嵌套子菜单。

代码类似于(为了演示简单而公开):

// Abstract base class
struct MenuItem
{
virtual ~MenuItem() {}
virtual void Execute() = 0;
virtual bool IsMenu() const = 0;
};

// Concrete classes
struct Action : MenuItem
{
void Execute() { /*...*/ }
bool IsMenu() const { return false; }
// ...
};

// ... other menu items

struct Menu : MenuItem
{
void Execute() { /* Display menu */ }
bool IsMenu() const { return true; }
// ...
std::vector<MenuItem*> m_items;
typedef std::vector<MenuItem*>::iterator ItemIter;
};

主菜单只是 Menu 的一个实例,一个单独的类跟踪菜单位置,包括如何进入和退出子菜单:

struct Position
{
Position( Menu* menu )
: m_menu( menu )
{
// Save initial position
m_pos.push_back( MenuPlusIter( m_menu, m_menu->m_items.begin() ) );
}

// Ignore error conditions for simplicity
void OnUpPressed() { m_pos.back().iter--; }
void OnDownPressed() { m_pos.back().iter++; }
void OnBackPressed() { m_pos.pop_back(); }

void OnEnterPressed()
{
MenuItem* item = *m_pos.back().iter;
// Need to behave differently here if the currently
// selected item is a submenu
if( item->IsMenu() )
{
// dynamic_cast not needed since we know the type
Menu* submenu = static_cast<Menu*>( item );

// Push new menu and position onto the stack
m_pos.push_back( MenuPlusIter( submenu, submenu->m_items.begin() ) );

// Redraw
submenu->Execute();
}
else
{
item->Execute();
}
}

private:
struct MenuPlusIter
{
Menu* menu;
Menu::ItemIter iter;

MenuPlusIter( Menu* menu_, Menu::ItemIter iter_ )
: menu( menu_ )
, iter( iter_ )
{}
};

Menu* m_menu;
std::vector<MenuPlusIter> m_pos;
};

关键函数是 Position::OnEnterPressed(),您可以在其中看到对 MenuItem::IsMenu() 的调用中的显式类型检查,然后转换为派生类型。有哪些选项可以重构它以避免类型检查和强制转换?

最佳答案

IMO,重构的起点是这些语句:

 1. m_pos.push_back( MenuPlusIter( m_menu, m_menu->m_items.begin() ) );

2. m_pos.push_back( MenuPlusIter( submenu, submenu->m_items.begin() ) );

在 IMO 看来,相同类型的陈述本身就表明需要重构它。

如果您可以在基类的方法中考虑 (1),然后在派生类中覆盖它以考虑特定行为 (2),那么您可以将它放在 Execute.

如果我错了请纠正我:这个想法是菜单有项目,每个项目都有一个与之关联的 Action ,当检测到某些事件时会触发该 Action 。

现在,当您选择的项目是子菜单时,Execute 操作的含义是:激活子菜单(我在一般意义上使用 activate)。当项目不是子菜单时,Execute 就是另一回事了。

我没有完全理解您的菜单系统,但在我看来您有一种层次结构菜单/子菜单(位置),以及一些根据节点类型触发的操作。

我设想的是菜单/子菜单关系是一个层次结构,允许您定义叶节点(当您没有子菜单时)和非叶节点(子菜单)。叶节点调用一个 Action ,一个非叶节点调用另一种处理激活子菜单的 Action (这个 Action 返回到菜单系统,所以你不需要在其中封装关于菜单系统的知识,你只是将操作中继到菜单系统)。

不知道这对你是否有意义。

关于c++ - 重构建议 : How to avoid type checking in this OO design,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6945169/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com