在C ++中使用抽象类和内部类是一种好习惯

时间:2012-03-23 18:04:59

标签: c++ inner-classes

我有一个类需要维护多个(目前为2或3个)上下文。这些背景在课堂外是不可见的。目前我的设计如下。在C ++中使用抽象类作为内部类是一种好习惯吗?如果您有任何其他选择,请提出建议。

在下面的示例中:问题是,当编写原始Car类时,方法(bar1和bar2)是在Sedan的上下文中编写的。现在我通过引入一种新的汽车类型(两厢车)来扩展汽车类。 bar1和bar2中的算法是针对Sedan类型编写的,不能用于Hatch-back类型。不幸的是,我无法更改现有的Car类(即构造函数或方法签名)。因此,我将在上面的示例中介绍Type类。

我的设计方法有意义吗?请在当前设计中提出更好的替代方案或潜在问题。

class Car {
public:
   explicit Car(/* sedan-type */) {
      // set context as Sedan
   }

   explicit Car(/* hatchback-type */) {
      // set context as Hatchback
   }

   void bar1() { context_type.bar1() };
   void bar2() { context_type.bar2() };

private:
   class Type {
      virtual void bar1() = 0;
      virtual void bar2() = 0;
   }
   class SedanType {
      void bar1() {}
      void bar2() {}
   }
   class HatchBackType {      
      void bar1() {}
      void bar2() {}
   }
}

2 个答案:

答案 0 :(得分:2)

这是一种很好的做法,特别是如果不同的类具有相似的命名策略并且您不想混淆它们。如果你不担心这一点,那么有时将它们放在课堂之外的工作就更少了。不过,它在Java习语中很常见。

通常你只看到基本内部类,如果它是抽象的。你绝对不应该有Car基于它们作为参数的不同构造函数。您没有分离您的疑虑,也没有制定政策substitutable

class Base {
public:
  Base(SomeAbstractPolicy *policy);
  struct SomeAbstractPolicy {
    virtual ~SomeAbstractPolicy() {}
    virtual void stuff() = 0;
  };
};

有时lazies会抱怨inversion of control这样的结构。将具体策略放在同一个头中或作为类中的静态助手可以是一个合理的妥协。

class Base {
public:
  Base(SomeAbstractPolicy *policy);
  struct SomeAbstractPolicy {
    virtual ~SomeAbstractPolicy() {}
    virtual void stuff() = 0;
  };
  static SomeAbstractPolicy *CreateAwesomeConcretePolicy();
  static SomeAbstractPolicy *CreateSweetConcretePolicy();
};

您可以更进一步,使用命名构造函数。

class Base {
public:
  Base CreateAwesomeBase();
  Base CreateSweetBase();

private:
  struct SomeAbstractPolicy {
    virtual ~SomeAbstractPolicy() {}
    virtual void stuff() = 0;
  };

  Base(SomeAbstractPolicy *policy);
  SomeAbstractPolicy *policy;
};

单位测试对于它的价值来说要困难得多。

如果根据您的抽象策略不能有一个构造函数,那么抽象属于Car,而不是策略。当你做这种改变时,它通常是一个更简单的解决方案。对此的代码味道是,您看到方法的整个主体是该类型的分支。

答案 1 :(得分:0)

为什么不继续扩展课程Car并覆盖bar1()bar2()方法。在他们的实现中,您不必调用父类的方法,因此您仍然可以获得所需的内容。

例如,让我们乘坐轿车:

class SedanCar : public Car {
  public :
     void bar1() {// do algorithm for sedan};
     void bar2() {// do algorithm for sedan};
}

现在任何调用bar1()bar2()的SedanCar实例都会执行轿车实施。