2017-02-12 18 views
2

Я пытаюсь сделать независимый от платформы код, поэтому я использую ООП. Например, в Windows, Mac OS X и Linux у вас могут быть окна, но на андроиде у вас есть представления, поэтому я пытаюсь их абстрагировать.Есть ли лучшее решение, чем dynamic_cast в этом случае?

я первый сделал класс для представления окна или представление, которое я назвал вид:

class View 
{ 
public: 
    virtual ~View() 
    {} 

    virtual void display() = 0; 
    virtual void hide() = 0; 
}; 

Теперь проблема заключается в том, что на Android, нет названия для взглядов в то время как на Windows, есть, так что я решил чтобы создать еще один класс:

class NameableView : public View 
{ 
public: 
    virtual void setName(const std::string& name) 
}; 

И, наконец, реализовать классы:

class WindowsView : public NameableView 
{ 
    /* Windows implementation */ 
} 

class AndroidView : public View 
{ 
    /* Android implementation */ 
} 

Затем мне нужно сделать код, который задает имя для представления, только если это возможно (если он наследует класс NameableView).

Так как я могу решить эту проблему? Я сначала подумал о dynamic_cast, но часто слышу, что слишком много dynamic_cast является индикатором проблемы с дизайном. Я новичок в C++, поэтому, возможно, я не думаю, что правильно, и я должен изменить весь дизайн.

+0

Сделать 'setName' реализованной функцией no-op в' View'? Это не так много отрывника от абстракции, чтобы иметь его там. – StoryTeller

+1

* «Я пытаюсь создать независимый от платформы код, поэтому я использую ООП». * - Для начала это плохая идея. Точка OOP, т. Е. ** виртуальных функций **, заключается в том, что вы можете выбирать и изменять реализацию чего-то во время работы приложения. –

+1

Это также некорректная идея попробовать и разработать абстрактную «базовую концепцию» для совершенно разных графических сред.Лучшим дизайном является разработка графических интерфейсов независимо друг от друга, каждый из которых зависит от потребностей их собственной системы и позволяет им использовать общий бизнес-логический компонент или бэкэнд, где это применимо. –

ответ

3

Я пытаюсь создать независимый от платформы код, поэтому я использую ООП.

Это не оптимальный подход - полиморфные иерархии и virtual функции позволяют различные конкретные типы объектов, которые наследуют от того же интерфейса ведут себя по-разному во время выполнения, но вы знаете, что платформа вы собираетесь предназначаться во время компиляции.

Вместо этого вы должны использовать статический полиморфизм и CRTP, чтобы обеспечить общий интерфейс, который должен удовлетворять каждая конкретная реализация на платформе.

template <typename TDerived> 
struct View 
{ 
    void display() { static_cast<TDerived&>(*this).display(); } 
    void hide() { static_cast<TDerived&>(*this).hide(); } 

    constexpr bool supportsSetView() const 
    { 
     return static_cast<TDerived&>(*this).supportsSetView(); 
    } 
}; 

В случае setName, вы должны обеспечить supportsSetView проверку на каждой платформе, которая возвращает true во время компиляции, если представление может быть названо. Затем вы выполняете эту проверку со стороны вызывающего абонента и вызываете только setName, если проверка проходит.

Пример использования:

#if defined(PLATFORM_ANDROID) 
struct AndroidView 
{ 
    // ... 
    constexpr bool supportsSetView() const { return false; } 
}; 

using MyView = View<AndroidView>; 
#else if defined(PLATFORM_WINDOWS) 
struct WindowsView 
{ 
    // ... 
    constexpr bool supportsSetView() const { return true; } 
    void setName(std::string x) { /* ... */ } 
}; 

using MyView = View<WindowsView>; 
#else 
#error "Unsupported platform." 
#endif 

вызывающего абонента сторона:

MyView currentView; 

if constexpr(currentView.supportsSetView()) 
{ 
    currentView.setName("something"); 
} 

Поскольку оценка if constexpr(...) «ы происходит во время компиляции, то код будет вызывать только setName, если она поддерживается MyView.