2016-05-05 3 views
4

Как решить проблему с классами и ввести как минимум максимально возможный код? Вот что у меня естьРазработка классов с виртуальными методами

Базовый интерфейс для всего

class IWindow 
    { 
    public: 
     virtual void Refresh() = 0; 
// another 100 virtual methods 
// ... 
    }; 

Этот интерфейс используется внутри библиотеки, которая не имеет ни малейшего представления о конкретной реализации.

Вот версия конкретной реализации

class ConcreteWindow : public IWindow 
    { 
    public: 
     void Refresh() override {} 
/// the other 100 overridden methods 
    }; 

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

class IDBDetail : public IWindow 
{ 
public: 
    virtual void DoDetail() = 0; 

}; 

и вот главная проблема, когда мы создаем конкретную inmplementation для него

class IGDBDetailWrapper : public IDBDetail, public ConcreteWindow 
{ 
public : 
    void DoDetail() {} 
}; 

конечно конкретный класс IGDBDetailWrapper является абстрактным, а потому, что он не выполняет эти 100 способов, но Я не хочу этого делать, я бы хотел просто повторно использовать реализацию от ConcreteWindow, все они работают с одним и тем же дескриптором окна, но это, конечно же, не будет компилироваться.

Я могу скопировать/вставить эти 100 методов из ConcreteWindow в IGDBDetailWrapper, но это перебор, потому что у меня могут быть еще 10 таких новых интерфейсов и конкретных реализаций.

Какой еще шаблон можно использовать здесь, чтобы помочь решить вопрос, а не повторять эти 100 методов снова и снова?

Thx

+2

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

+0

Почему бы просто не наследовать от ConcreteWindow? –

+0

Это просто плохой дизайн библиотеки, потому что 100 методов в базовом классе ужасны, а отношения наследования между 'IDBDetail' и' IWindow' выглядят неправильно. Вы не найдете чистого решения; любой клиент этой библиотеки должен будет использовать одно обходное решение или другое. –

ответ

2

Вы можете использовать виртуальное наследование. Если мы будем игнорировать этот факт должен IDBDetail наследовать от IWindow или нет, мы могли бы использовать виртуальное наследование для решения проблемы с текущей архитектуры:

class IWindow 
    { 
    public: 
     virtual void Refresh() = 0; 
// another 100 virtual methods 
// ... 
    }; 

    class ConcreteWindow : virtual public IWindow 
    { 
    public: 
     void Refresh() override {} 
/// the other 100 overridden methods 
    }; 

class IDBDetail : virtual public IWindow 
{ 
public: 
    virtual void DoDetail() = 0; 

}; 

class IGDBDetailWrapper : public IDBDetail, public ConcreteWindow 
{ 
public : 
    void DoDetail() {} 
}; 

Теперь компилятор будет использовать реализацию для 101 абстрактного метода из ConcreteWindow

+0

, который решил проблему. Спасибо! – Eugen

4

Ваша конструкция работает в diamond problem.

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

class IDBDetail : public IWindow { 
    public: 
    virtual void DoDetail() = 0; 

}; 

Из описания вашего интерфейса IDBDetail выглядит IDBDetail не должны наследовать от IWindow. Если его просто добавить дополнительные функции, то IDBDetail не обязательно должен быть IWindow. Это просто нужно понять IWindow. Например, чтобы обезьяна делала что-то особенное, тренер не должен быть обезьяной.

Decorator pattern может быть тем, что вы ищете.

+1

Это не сработает, потому что внутри этой библиотеки метод использует указатель на IDBDetail для доступа к методам из IWindow. К сожалению, у меня нет возможности изменить эту библиотеку. – Eugen

+0

@ Eugen Ok. Но вы по-прежнему не можете идти с текущей моделью наследования, если вы используете одну из альтернатив в своем вопросе. Потому что проблема с алмазами – bashrc

2

Вы должны переопределить все методы абстрактного класса, другого пути нет. На самом деле вы не должны создавать абстрактный класс из 100 методов здесь и все. Возможно, вы можете разделить его на несколько более мелких абстрактных классов? Однако в этом случае IDBDetail не должен наследовать после того, как IWindow и IGBDDetailWrapper также не должны наследовать после IWindow - и мы здесь.

+0

Может быть, разделение на более мелкие классы может помочь. Я должен проверить это. – Eugen

3

Во-первых, если вы используете Visual Studio есть инструменты рефакторинга, которые могут помочь вам с этим автоматизации, что может быть иначе утомительной задачей, второй:

мне много бессмысленно делать то же самое:

class IDBDetail : public IWindow 
{ 
public: 
    virtual void DoDetail() = 0; 

}; 

Я хотел бы сделать что вместо

class IDBDetail 
{ 
public: 
    virtual void DoDetail() = 0; 

}; 

Интерфейсы должны использоваться для абстрагироваться от ответственности, поэтому загромождения на интерфейс с уже сотни м Этод с дополнительными методами является симптомом плохого дизайна.

Однако можно использовать композицию, один раз для всех, так что вы создаете один раз класса, решить эту проблему для вашего, и вы можете позже повторное что

class IDBDetailWithConcreteWindow: public IDBDetail{ 

    IWindow * concreteWindow; 
public: 
    IDBDetailWithConcreteWindow(IWindow * window){ 
     concreteWindow = window; 
    } 

    void Refresh() override{ 
     concreteWindow->Refresh(); 
    } 
} 

И, наконец, в любой полученный класса вы только реализовать методы из IDBDetail

IGDBDetailWrapper: public IDBDetailWithConcreteWindow{ 
public: 

    void DoDetail() override { } 
} 

преимущество этого решения заключается в том, что если у вас есть внешние ограничения (например, плохой Designe d уже существующая база кода), вы все равно можете использовать его, в то время как верхнее решение не будет работать, если вы не можете изменить интерфейс IDBDetail.

2

Это не решит проблему, но, по крайней мере, вы можете перенаправить исполнения ордеров себя:

class IGDBDetailWrapper : public IDBDetail, public ConcreteWindow 
{ 
public: 
    virtual void DoDetail() override { /*work here*/ } 

    virtual void Refresh() override { ConcreteWindow::Refresh(); } 
    //another 100 methods 
}; 

Вы можете сделать блок таких перенаправлений как компилятор #DEFINE и повторить столько раз, сколько вы хотите.

+0

Как @DarioOO сказал, что вы можете использовать инструменты рефакторинга Visual Studio, чтобы автоматически создавать перенаправления. –

3

@bashrc является правильным, но это должно быть возможно решить проблему с виртуальным наследованием:

class ConcreteWindow : public virtual IWindow {...} 

class IDBDetail : public virtual IWindow {...} 

Эта статья в Википедии на virtual inheritance государства решение, как хорошо.

Смежные вопросы