2015-06-26 3 views
2

У меня есть иерархия классов:Множественные иерархии подкласса

class AbstractProcess 
{ 
    virtual void Do() = 0; 
}; 

class BuildProcess : public AbstractProcess 
{ 
    virtual void Do(); 
}; 

class UpdateProcess : public AbstractProcess 
{ 
    virtual void Do(); 
}; 

Однако, теперь я хочу ввести 2 новых подклассов как процесс также может быть ручной или автоматический (4?). Следующие выглядит слишком долго наматывается:

class ManualBuildProcess : public BuildProcess 
{ 
    virtual void Do(); 
}; 

class ManualUpdateProcess : public UpdateProcess 
{ 
    virtual void Do(); 
}; 

class AutomatedBuildProcess : public BuildProcess 
{ 
    virtual void Do(); 
}; 

class AutomatedUpdateProcess : public UpdateProcess 
{ 
    virtual void Do(); 
}; 

Это будет только хуже, если я хочу, чтобы ввести дополнительные подклассы либо сборки/Update или Manual/Автоматизированные процессы.

Есть ли лучший дизайн?

+0

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

+0

Внедрение ручных/автоматизированных процессов делает бывшие классы абстрактными? Я имею в виду, вы все еще хотите использовать плохой «BuildProcess» без указания, ручной или автоматизированный? –

+0

Энди Т - да, это очень хороший момент. Подчиненные и автоматизированные подклассы теперь станут абстрактными. –

ответ

1

Я могу предложить два подхода.

Один сделать ваш Manual...Process шаблонный:

template<class Process> class ManualProcess: public Process { 
    virtual void Do() { 
     ... 
     // you can access base class data: 
     Process::Do(); 
    } 
}; 

// use like 
ManualProcess<BuildProcess> process; // instead of ManualBuildProcess 

Во-вторых, есть две иерархии и предпочитают состав по наследству, что-то вроде

class Operator; 
class ManualOperator: public Operator... 
class AutomaticOperator: public Operator... 

class Process { 
    Operator* operator; 
    ... 
}; 
class BuildProcess: public Process... 
class UpdateProcess: public Process... 
... 

или наоборот (Operator держит указатель на Process) или даже симметричным способом с Operator s и Process es, не зная друг о друге, но с третьим классом, содержащим указатель на Operator и указатель на Process.

Конечно, это все применимо только в том случае, если существует общий код для всех случаев Manual и некоторый код, общий для всех случаев Build и т. Д. Если каждая из этих версий имеет свой собственный код, то у вас, очевидно, нет выбора.

0

C++ допускает множественное наследование. Это может сделать иерархию классов лучше, но с таким небольшим контекстом трудно сказать, что лучше.

Но вы можете подумать о том, что AutomatedProcess и ManualProcess можно использовать как подклассы из AbstractProccess, так же как и процесс сборки и UpdateProcess.

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

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

0

Я бы минимизировал наследование здесь и использовал композицию. Manual/Automated - один самолет, Build/Update - другой. Кажется, что ваши Process нуждаются в стратегиях, определенных в обеих плоскостях. Это может быть сделано как:

struct Executor; 
struct Operator; 

template <typename ExecutorT, typename OperatorT> 
struct Process 
{ 
    std::unique_ptr<Executor> executor_; 
    std::unique_ptr<Operator> operator_; 

    Process(): 
     executor_(new ExecutorT()), 
     operator_(new OperatorT()) 
    {} 

    void Do() 
    { 
     executor_->Do(); 
     operator_->Do(); 
     // do something else 
    } 
}; 

Остальное довольно просто, и теперь вы можете сосредоточиться на бизнес-логики:

struct Executor 
{ 
    virtual void Do() = 0; 
}; 

struct Manual : Executor 
{ 
    virtual void Do() override {} 
}; 

struct Automated : Executor 
{ 
    virtual void Do() override {} 
}; 

struct Operator 
{ 
    virtual void Do() = 0; 
}; 

struct Build : Operator 
{ 
    virtual void Do() override {} 
}; 

struct Update : Operator 
{ 
    virtual void Do() override {} 
}; 
0

Помимо vaious объектно-ориентированные подходы, такие как, например, strategy pattern, вы можете Ало использовать шаблоны в C++:

template <typename Action> class Process { 
    Action a; 
    public: 
     Process(const Action& action): a{action} {}; 
     void do() { a.do(); }; 
}; 

template <typename Interface> class BuildAction { 
    Interface i; 
    public: 
     BuildAction(const Interface& interface): i{intreface} {}; 
     BuildAction(const BuildAction& other): i{other.i} {}; 
     void do() { i.build(); }; 
}; 

template <typename Interface> class UpdateAction { 
    Interface i; 
    public: 
     UpdateAction(const Interface& interface): i{intreface} {}; 
     UpdateAction(const UpdateAction& other): i{other.i} {}; 
     void do() { i.update(); }; 
}; 

class ManualInterface { 
    public: 
     void build(); 
     void update(); 
}; 

class AutomaticInterface { 
    public: 
     void build(); 
     void update(); 
}; 

typedef Process<BuildAction<ManualInterface>>  ManualBuildProcess; 
typedef Process<BuildAction<AutomaticInterface>> AutomaticBuildProcess; 
typedef Process<UpdateAction<ManualInterface>> ManualUpdateProcess; 
typedef Process<UpdateAction<AutomaticInterface>> AutomaticUpdateProcess; 

я мог бы иметь некоторые неоптимальные Предположения для вашего фактического USECASE.Вы могли бы найти более эффективные структуры, как например .:

typedef Process<BuildAction, ManualInterface> ManualBuildProcess; 

Конечно, вы можете комбинировать шаблоны с ОО-шаблонов, а также:

Process<ManualInterface> myManualBuildProcess{BuildStrategy{}}; 

BTW .: Я использовал C++ 11 синтаксис. Если у вас есть только C++ 98, вам придется соответствующим образом адаптировать код.

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

  • Нет связанных вопросов^_^