【发布时间】:2020-02-03 01:08:05
【问题描述】:
我被要求实现一个接口,我想知道什么是尽可能多地分解代码的最佳策略。
这是接口定义(我不应该改变它):
#include <string>
class BaseIf
{
public:
virtual ~BaseIf() {}
virtual std::string getName() = 0;
};
class IntIf : public BaseIf
{
public:
virtual ~IntIf() {}
virtual int getValue() = 0;
};
class FloatIf : public BaseIf
{
public:
virtual ~FloatIf() {}
virtual float getValue() = 0;
};
我最终会得到IntImpl(实现IntIf)和FloatImpl(实现FloatIf)。但我想知道我应该把这两个类共有的任何代码放在哪里(比如name 属性管理或BaseIf 所需的任何其他东西,实际上比这个MCVE 大得多)。
如果我使用公共代码创建BaseImpl(实现BaseIf 的getName 函数),并从它派生IntImpl(和IntIf),那么我还需要实现getName因为它被报告为未实施。而且我还得到了BaseIf的双重继承...
我想知道 Pimpl 模式是否会有所帮助,然后 IntImpl 将有一个 BaseImpl 对象作为属性(并且仅从 IntIf 派生),但是我需要在 @987654339 中实现 getName @ 以“转发”对BaseImpl 属性的调用。因为BaseIf 实际上有很多虚函数,所以维护起来真的很痛苦。
是否没有聪明的解决方案/模式可以在一个共同的地方只实现一次getName?还是只是界面不好,应该重做?
【问题讨论】:
-
根据您的其他要求和设计,似乎更好的选择是这里的模板和模板专业化。或者可能是一个没有任何特化或继承的通用“数字”模板。
-
关于你当前的代码,除非你有多个“Int”实现都继承自
IntIf,否则“Int”真的不需要单独的接口和实现类。 -
我建议实现仍然保持纯虚拟成员的派生接口是“糟糕的设计”。正如其他人所说,模板在这里会更好地工作(但是,您显然不能更改设计)。
-
添加派生接口只是愚蠢的。恕我直言,它完全破坏了界面范例的全部意义。您通常会从您的界面派生 usable 类 - 但有时,“中间”可能会有所帮助。例如,在这里,这样的中间体将定义
getName成员。 -
为什么对不同“类型”的处理不同?尤其是
float和int的处理为什么会有这么大的区别?从数学的角度来看,整数和实数 (float) 之间并没有太大区别,导致您的实现出现巨大差异的设计决策或要求是什么?对我来说,这似乎是需求分析和最终设计的问题。
标签: c++ inheritance design-patterns