如果我有一个抽象类和该类的派生类,根据良好和实用的设计实践,派生类不应该提供额外的公共方法(它们应该只实现抽象类并可选地覆盖父方法),我是否更正?
此外,对于每个派生类具有不同的构造函数方法签名是否可以接受?
如果我有一个抽象类和该类的派生类,根据良好和实用的设计实践,派生类不应该提供额外的公共方法(它们应该只实现抽象类并可选地覆盖父方法),我是否更正?
此外,对于每个派生类具有不同的构造函数方法签名是否可以接受?
就个人而言,我认为两者都没有问题。
至于派生类的额外公共方法:
在许多情况下,这方面的用处有限。当类已被强制转换或设置为对基类的引用时,额外的方法将不可用,这严重限制了这种做法的实用性。话虽如此,这种方法并没有什么特别的错误。子类旨在添加特定行为 - 有时,在类层次结构中,子类中有不适合基类的新行为。如果子类要经常单独使用,那么在方法中对额外行为进行建模似乎是完全合理的。
至于构造函数签名 -
我也认为这没有问题。子类通常需要比抽象类更多的信息才能进入可用状态。话虽如此,我通常会确保在基类中实现每个构造函数,并添加子类所需的新参数。
话虽如此:
除非有充分的理由,否则我会避免使用比基类更少的参数的子类构造函数......为什么我能够在更通用的情况下而不是在特定情况下指定一些东西?我发现当子类具有与基类完全不同的构造选项时,通常会感到困惑。
这就是派生类的美妙之处。
虽然 Pen 类可能具有 write() 函数,但扩展 Pen 的 RetractablePen 类也可能具有retractPoint() 函数。
当您扩展一个类时,它意味着——从字面上看——扩展它的功能。
一般没问题。
您要避免的是在泛型中使用特定的。IE
foreach(Animal a in myFarm.Animals)
{
a.Feed();
// this is a bit grim
if( a is Horse )
{
((Horse)a).CleanStable();
}
}
所以这不是添加公共方法的行为,而是你从哪里调用它们。
向派生类添加额外的公共方法是完全可以接受的。给他们不同的构造器也是完全可以接受的。(事实上,这很常见。)
不,添加额外的公共方法是完全合理的(有时在设计上非常必要)。Shape
考虑具有Location
成员和Size
方法的抽象基类的(完全人为的)情况。例如,当您Polygon
从派生时Shape
,您可能希望添加一个名为 的公共方法GetNumberOfSides()
;但是当您Circle
从Shape
.
同样,派生类型可能有非常不同的构造要求;在定义抽象基类时,不可能知道所有的要求是什么,所以请随意使用不同的签名。仅仅因为你的派生类型对于抽象基类是多态的,并不意味着该基类对你如何实现该基类中定义的抽象施加了严格的限制。你可以随心所欲地做它。
如果你尊重Liskov 替换原则,你可以为所欲为。
当然,在派生类中添加方法一点也不违反原则。
派生类不应提供额外的公共方法
狗能做动物不能做的事吗?
此外,对于每个派生类具有不同的构造函数方法签名是否可以接受?
这里没有问题。派生类型不需要匹配其兄弟姐妹或父母的构造函数签名。
这不仅是可以接受的,而且构造函数通常需要不同。例如,如果我们有一个 (immutable)Rectangle
类并用 (immutable) 扩展它Square
,Square 的构造函数应该是(暂时使用 Java)
public Square(double size)
而构造函数Rectangle
将是
public Rectangle(double width, double height)
需要发生的是子类构造函数应该调用一些适当的超类构造函数。
至于额外的公共方法,可能取决于用途。对于 Square 案例,我不会添加任何额外的方法。然而,在 Java 中,有一个子类PrintWriter
,Writer
其目的是添加一些方便的方法。在这种情况下,我认为还可以(Java 肯定有一些不好的例子,但我认为这不是其中之一)。我还希望为容器/子部分类型提供一些额外方法的可能性。
您不应该做的是以违反超类期望的方式更改超类方法。