我正在尋找重構的建議以改進我的類設計並避免類型檢查。重構建議:如何避免在此OO設計中進行類型檢查
我正在使用Command設計模式來構建菜單樹。菜單中的項目可以是各種類型的(例如,立即動作[比如「保存」],切換開/關屬性,其根據其狀態(例如「斜體」等)隨着檢查/圖標顯示。重要的是,還有子菜單,其中取代屏幕上當前菜單的(而不是顯示在側面)。這些子菜單當然包含它們自己的菜單項列表,這些菜單項可以有更多的嵌套子菜單。
的代碼是一樣的東西(所有公衆簡單的演示):
// 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;
};
的主菜單就是菜單的一個實例,以及一個單獨的類保留菜單位置的軌跡,包括如何去進,出子菜單:
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;
};
的主要功能是位置:: OnEnterPressed(),在那裏你看到在調用菜單項)一個明確的類型檢查:: IsMenu(然後強制轉換爲派生類型。有什麼方法可以重構這個以避免類型檢查和轉換?
我不沒有看到演員的問題。事實上,我沒有看到一個聰明的方式來消除它,而不會混淆代碼。畢竟,當你遇到子菜單時,你會希望發生不同的事情,不是嗎?地獄,我甚至會用'dynamic_cast'去掉這個'IsMenu'方法。 –