1

我目前处于类库的设计阶段,偶然发现了一个类似于“使用没有 RTTI 的中央管理器管理不同的类”或“避免 dynamic_cast 的模式”的问题。

想象有一个类层次结构,其中有一个基类Base和两个作为Base子类的DerivedADerivedB类。在我的库中的某个地方,将有一个类需要保存DerivedADerivedB类型的对象列表。进一步假设此类将需要根据类型对两种类型执行操作。显然我会在这里使用虚函数来实现这个行为。但是如果我需要管理类来给我DerivedA类型的所有对象呢?

这是一个糟糕的类设计的指标,因为我只需要对类层次结构的一个子集执行操作吗?

或者它只是意味着我的管理类不应该使用Base列表而是两个列表 - 一个用于DerivedA,一个用于DerivedB?因此,如果我需要对这两种类型执行操作,我将不得不遍历两个列表。在我的情况下,需要向层次结构添加新子类的可能性非常低,目前的数量约为 3 或 4 个子类。

4

3 回答 3

3

但是,如果我需要管理类来给我所有 DerivedA 类型的对象呢?

这是一个糟糕的类设计的指标,因为我只需要对类层次结构的一个子集执行操作吗?

更有可能是而不是。如果您经常需要这样做,那么质疑层次结构是否有意义是有意义的。在这种情况下,您应该将其分成两个不相关的列表。

另一种可能的方法是也通过虚拟方法来处理它,例如DeriveB,对于不影响它的方法,将有一个无操作实现。不知道更多信息就很难说。

于 2013-03-20T10:58:50.147 回答
2

如果您将必须以不同方式处理的对象存储(指向)在一起,这肯定是设计不良的标志。

但是,您可以将这种不同的行为实现为基类中的空函数或使用访问者模式。

于 2013-03-20T10:58:32.210 回答
-1

您可以通过多种方式做到这一点。

  • 尝试使用dynamic_cast特定的类(这是一个蛮力解决方案,但我只将它用于接口,将它用于类是一种代码气味。它会工作。)
  • 执行以下操作:

    class BaseRequest {};
    class DerivedASupportedRequest : public BaseRequest {};
    

    然后修改您的类以支持该方法:

    // (...)
    void ProcessRequest(const BaseRequest & request);
    
  • bool TryDoSth()在基类中创建虚方法;DerivedB将始终返回 false,同时DerivedA将实现所需的功能。

  • 上述替代方案: Create method Supports(Action action),其中Action是定义可能动作或动作组的枚举;在这种情况下,调用DoSth()不支持给定功能的类应该会导致抛出异常。
  • 基类可能有方法ActionXController * GetControllerForX()DerivedA将返回实际控制人,DerivedB将返回nullptr.
  • 同样,基类可以提供方法:BaseController * GetController(Action a)

你问,这是否是一个糟糕的设计。我相信,这取决于有多少功能是常见的,又有多少是不同的。如果您有 100 种常用方法而只有一种不同,那么将这些数据保存在单独的列表中会很奇怪。但是,如果不同方法的数量很明显,请考虑更改应用程序的设计。这可能是一般规则,但也有例外。不知道上下文很难说。

于 2013-03-20T11:06:58.257 回答