我正在寻找有关重构的建议,以改进我的类设计并避免类型检查。
我正在使用命令设计模式来构建菜单树。菜单中的项目可以是各种类型(例如,立即操作[如“保存”]、根据其状态显示带有检查/图标的切换开/关属性[如“斜体”]等)。至关重要的是,还有子菜单,它们替换屏幕上的当前菜单(而不是显示在旁边)。这些子菜单当然包含它们自己的菜单项列表,其中可能有更多嵌套的子菜单。
代码类似于(为简单起见,全部公开):
// 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() 的调用中的显式类型检查,然后转换为派生类型。有哪些选项可以重构它以避免类型检查和强制转换?