【问题标题】:Multiple subclass hierarchy多个子类层次结构
【发布时间】:2015-06-26 14:05:34
【问题描述】:

我有类层次结构:

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();
};

如果我想引入构建/更新或手动/自动化流程的其他子类,情况只会变得更糟。

有更好的设计吗?

【问题讨论】:

  • C++ 支持多重继承,因此您可以有另一个基类来处理手动工作的常用功能,以及一个处理自动化工作的常用功能的基类。这意味着更多的类,但也可能意味着更好的抽象,以及叶类中更少的代码。
  • 引入手动/自动化流程是否会使以前的类抽象化?我的意思是,你还想使用可怜的BuildProcess 而不指定它是手动的还是自动的?
  • Andy T - 是的,这是一个很好的观点。 Manual 和 Automated 子类现在将变得抽象。

标签: c++ oop subclassing


【解决方案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 的指针),或者甚至以对称方式与 Operators 和 Processes 不知道彼此,但与第三类持有指向Operator 的指针和指向Process 的指针。

当然,这一切都适用于所有Manual 案例有一些通用代码和所有Build 案例有一些通用代码等情况。如果这些版本中的每一个都有自己的代码,那么你显然没有选择。

【讨论】:

    【解决方案2】:

    C++ 允许多重继承。这可能会使类层次结构更好,但在如此少的上下文中很难说什么是最好的。

    但您可能会认为将 AutomatedProcess 和 ManualProcess 直接作为 AbstractProccess 的子类,就像 Build Process 和 UpdateProcess 一样。

    但是,如果确实存在所有组合,那么您将必须为每个组合创建一个类,仍然会产生您现在拥有的类数量。

    您可能想了解自动/手动流程的作用。 它可能不需要是一个单独的类,但它可以是一个类的成员。

    【讨论】:

      【解决方案3】:

      我会在这里最小化继承并使用组合。 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 {}
      };
      

      【讨论】:

        【解决方案4】:

        除了各种面向对象的方法,例如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;
        

        对于您的实际用例,我可能有一些次优假设。您可能会发现更好的结构,例如:

        typedef Process<BuildAction, ManualInterface> ManualBuildProcess;
        

        当然,您也可以将模板与 OO 模式结合起来:

        Process<ManualInterface> myManualBuildProcess{BuildStrategy{}};
        

        顺便说一句:我使用了 C++11 语法。如果您只有 C++98,则必须相应地调整代码。

        【讨论】:

          猜你喜欢
          • 2019-02-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多