私はクラスデザインを改善し、型チェックを避けるためにリファクタリングに関するアドバイスを探しています。リファクタリングのアドバイス:このOOデザインの型チェックを回避する方法
私はコマンドデザインパターンを使用してメニューツリーを構築しています。メニュー内のアイテムは、様々なタイプ(例えば、「保存」のような即時アクション、その状態に応じてチェック/アイコンで表示されるトグルオン/オフプロパティ[イタリック体]など)であってもよい。重大なことに、サブメニューもあります。は、画面上の現在のメニューを(代わりに表示するのではなく)に置き換えます。これらのサブメニューには、独自のメニュー項目のリストが含まれています。これは、より多くのネストされたサブメニューを持つ可能性があります。
コードは(プレゼンテーションの簡略化のためのすべてのパブリック)のようなものです:
// 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;
};
キー機能を使用すると、MenuItemにへの呼び出しで明示的な型チェックを参照してください位置:: OnEnterPressed()、:: IsMenu()してから派生型へのキャストです。タイプチェックを避けてキャストするためにこれをリファクタリングするオプションは何ですか?
私はドン」キャストの問題を参照してください。実際には、私はコードを乱雑にすることなくそれを削除するスマートな方法を見て失敗します。結局のところ、あなたはサブメニューに出会った時に何か別のものが欲しいのですか?地獄、私は 'dynamic_cast'と一緒に行くと、この' IsMenu'メソッドを削除します。 –