给定遗留代码,系统具有以下类层次结构:
Base
^
|
----------+---------------
^ ^ ^ ^ ^
| | | | |
A1 B1 C1 D1 E1
^ ^ ^ ^ ^
| | | | |
A2 B2 C2 D2 E2
.......
^ ^ ^ ^ ^
| | | | |
An Bn Cn Dn En
该层次结构表示某个特定域中的消息。
Base 类当然是所有消息的基类。 A1..E1 是属于域版本 1 的消息,A2..E2 是属于版本 2 的消息,依此类推。请注意,An 必须直接继承自 An-1,因为 An 会覆盖 An-1 的特定方法。
有一些功能对于所有消息都是通用的,因此它被定义为Base::PerformFunctionality。部分功能仅特定于版本n,因此存在虚函数Base::SpecificPartOfFunctionality,由Base::PerformFunctionality调用。
所以我的问题是如何通过所有 An..En 覆盖 Base::SpecificPartOfFunctionality。
我看到了 2 种可能的解决方案,但我不太喜欢:
-
在每个 An..En 中实现 Base::SpecificPartOfFunctionality。
这个解决方案的问题是每个类的实现应该完全相同,所以我只是重复代码。
另一个问题是,如果引入新类 Fn,开发人员可能会忘记实现SpecificPartOfFunctionality。
-
引入从 Base 派生的 BaseN 类,同时每个 An..En 也从 BaseN 派生:
类 BaseN : public Base {
//...
具体部分功能(){...}
};
An 类:公共 An-1,公共 BaseN { .. }
此解决方案的问题在于它引入了钻石问题。
另一个问题是,如果其他版本m也需要覆盖Base::SpecificPartOfFunctionality,将会发生什么情况。在解决方案之后,我们将引入BaseM,它将覆盖Base::SpecificPartOfFunctionality。因此,将为BaseN 或BaseN 的An 调用哪个SpecificPartOfFunctionality。一团糟。
有什么建议吗?
Given legacy code, the system has the following hierarchy of classes:
Base
^
|
----------+---------------
^ ^ ^ ^ ^
| | | | |
A1 B1 C1 D1 E1
^ ^ ^ ^ ^
| | | | |
A2 B2 C2 D2 E2
.......
^ ^ ^ ^ ^
| | | | |
An Bn Cn Dn En
The hierarchy represents messages in some specific domain.
Base class is of course base class of all messages. A1..E1 are messages belonging to version 1 of the domain, A2..E2 to version 2, and so on. Please note that An must inherit directly from An-1, since An overrides specific methods of An-1.
There's some functionality that is common to all messages, so it's defined as Base::PerformFunctionality. Some part of the functionality is specific to version n only, so there's virtual function Base::SpecificPartOfFunctionality, which is called by Base::PerformFunctionality.
So my problem is how to override Base::SpecificPartOfFunctionality by all An..En.
I see 2 possible solutions, which I don't like too much:
-
Implement Base::SpecificPartOfFunctionality in each and each An..En.
The problem with this solution is that the implementation should be exactly same for each class, so I just repeat the code.
Additional problem is that if a new class Fn is introduced, developer may forget to implement SpecificPartOfFunctionality.
-
Introduce BaseN class deriving from Base, while each An..En derive from BaseN too:
class BaseN : public Base {
//...
SpecificPartOfFunctionality() { ...}
};
class An: public An-1, public BaseN { .. }
The problem with this solution is that it introduces diamond problem.
Additional problem is what will happen if some other version m needs to override Base::SpecificPartOfFunctionality too. Following the solution we'll introduce BaseM, which will override Base::SpecificPartOfFunctionality. So which SpecificPartOfFunctionality will be called for An - of BaseN or of BaseN. It's complete mess.
Any suggestions?
发布评论
评论(2)
唯一的缺点是您无法轻松地在当前 C++ 中转发构造函数,并且为了简单起见,可能始终使用 A2 和 B2 的默认构造函数。
然而,在 C++0x 中,您可以转发构造函数:
你误解了一些东西。 An 不需要直接从 An-1 继承。例如,这很好用:
请记住,如果这不起作用,那么您的 An 首先无法从您的基类重写 SpecificPartOfFunctionality!在您的任何示例中, An 都不直接从 Base 继承。
The only downside is you can't easily forward constructors in current C++, and are probably going to always use the default constructor for A2 and B2 just for simplicity.
In C++0x, however, you can forward constructors:
You have misunderstood something. An does not need to inherit directly from An-1. For example, this works just fine:
Remember that if this didn't work, then your An couldn't override SpecificPartOfFunctionality from your Base class in the first place! An doesn't directly inherit from Base in any of your examples.
在全局范围内定义一个实现该功能的友元函数,并且让
SpecificPartsOfFunctionality
除了调用它之外什么也不做。例如,严格来说,FunctionalityN 甚至不必是朋友,尽管它会让事情变得更容易。这使得扩展到 Fn、Gn 等变得简单,随后用
NewFunctionalityN
替换FunctionalityN
也非常容易。Define a friend function at global scope which implements the functionality, and have
SpecificPartsOfFunctionality
do nothing more than call it. E.g.Strictly speaking FunctionalityN wouldn't even have to be a friend, though it would make things easier. This makes extending to Fn, Gn, etc. straightforward and subsequently replacing
FunctionalityN
withNewFunctionalityN
pretty easy, too.