我一直在阅读Jeffrey Richter通过C#编写的CLR,他认为在基类中定义方法时,如果有一种方法要声明为虚拟,并且它有一些方便的重载,那么最多复杂方法应该是虚方法,其他方法应该保留为非虚方法。以下是他给出的例子:
public class Set {
private Int32 m_length = 0;
// This convenience overload is not virtual
public Int32 Find(Object value) {
return Find(value, 0, m_length);
}
// This convenience overload is not virtual
public Int32 Find(Object value, Int32 startIndex) {
return Find(value, startIndex, m_length - startIndex);
}
// The most feature-rich method is virtual and can be overridden
public virtual Int32 Find(Object value, Int32 startIndex, Int32 endIndex) {
// Actual implementation that can be overridden goes here...
}
// Other methods go here
}
这里的理性是什么?
答案 0 :(得分:3)
答案是 - DRY principle - a single source of truth。方法A最复杂。 B,C和D都使用其功能的子集。所以程序员以这种方式创建,并且所有进一步的代码修改都基于你保持A,B,C,D之间关系的假设。如果你允许所有的B,C,D都是可以覆盖的,那么你就打破了这个想法。在课堂上。
代码可读性受损,人们阅读您的基类,撰写如何工作的图片,然后阅读您的课程,并确定他们刚刚学到的内容与您的实施不同。让团队努力工作。此外,当你5年后阅读你的代码时(如果它需要发生)。
答案 1 :(得分:2)
原因是所有更简单的方法都是通过调用虚方法实现的。如果这些是虚拟的,你可能会破坏这份合同。通过仅允许您更改此类的实现特化,将遵循这些方法的相同合同。
答案 2 :(得分:0)
我同意杰弗里的意见;将虚拟变成最复杂的成员是有意义的,因为对'较小'复杂成员的调用将调用最复杂的成员,因为它们是通过方法链调用的。此外,它表明最复杂的成员可能是包含执行该函数所需的所有参数而没有任何外部依赖性的成员。
如果可以的话,我稍后会对此进行扩展。
答案 3 :(得分:0)
只有一个实现,其他重载只是转发一个呼叫。使那个virtual
有意义,因为在实现被覆盖时转发仍然有效。