【发布时间】:2008-11-28 21:09:30
【问题描述】:
刚刚在我正在阅读的一本关于 OOP 的书中看到这句话,
一个孩子只能增强 功能和添加功能。 绝不允许儿童移除 功能。如果你确实发现一个 孩子需要删除功能, 这表明孩子 应该出现在父级之前 继承层次结构!
但我的问题是,这不是覆盖的作用吗?
【问题讨论】:
标签: inheritance overriding parent-child
刚刚在我正在阅读的一本关于 OOP 的书中看到这句话,
一个孩子只能增强 功能和添加功能。 绝不允许儿童移除 功能。如果你确实发现一个 孩子需要删除功能, 这表明孩子 应该出现在父级之前 继承层次结构!
但我的问题是,这不是覆盖的作用吗?
【问题讨论】:
标签: inheritance overriding parent-child
您可以通过覆盖来删除功能。但通常你用它来改变行为。让班级按应有的方式行事。
如果行为被移除,那么它通常是一个糟糕的类设计的标志。
【讨论】:
孩子不能删除功能 - 它可以改变它,但你不能,比如说,将公共方法设为私有。
继承的要点是您可以像处理父级一样处理子级。如果你有一个 'Person' 超类和一个 'Employee' 子类,那么 Employee 类没有 Breath() 方法是没有意义的。
【讨论】:
在覆盖方法时,可以在覆盖期间的某个时间点调用父实现,因此使用覆盖向父实现添加功能。
【讨论】:
没有。实际上你会增加功能(以消极的方式)
假设您的新功能是“什么都不做”,但方法,您的代码的客户端看到的仍然是相同的接口
你的子类不能删除其父类的方法。
这是可能的
class Parent {
public void method_one(){
print "Hello";
}
}
class Child extends Parent {
public void method_one(){
// do nothing
}
}
但这不是:
class Parent {
public void method_one(){
print "Hello";
}
}
class Child extends Parent {
// Attempt remove the method visibility, thus remove funcionality
private void method_one(){
// do nothing
}
}
【讨论】:
这就是为什么覆盖(以及一般来说,任何虚拟成员)应该非常小心地完成的事情...... 其实一般来说,在重写的时候,应该尽量同时编写基类和派生类,让派生类实现先调用基类实现,然后再执行它的附加功能……
但是这个原则并没有在 OO 语言中强制执行,而且经常被违反......
为什么这不好的例子
假设您有 CompanyA 设计的类型(类)电话
namespace CompanyA {
class Phone {
public void Dial() {
// do work to dial the phone here
}
}
}
没有 iagine 公司 B 定义了另一种类型 BetterPhone,它使用公司 A 的电话作为基本类型...
namespace CompanyB {
class BetterPhone: CompanyA.Phone {
public void Dial() {
Console.WriteLine("BetterPhoneDial");
EstablishConenction();
base.Dial();
}
}
}
现在 CompanyA,其 Phone 类正在被其他公司(公司 C、D 等)使用,决定建立连接是该类中有用的东西,并修改 CompanyA.Phone,添加 EsatblishCONnection()方法也是如此,也许有不同的实现......在我们有了“new”关键字之前,这种情况会破坏 CompanyB 的 BetterPhone 类......当他们第一次尝试使用新的基类时。
【讨论】:
如果您的孩子需要删除父级的功能,则必须将父级声明为接口。 因为接口是定义必须由其实现者遵守的契约的机制。
例如
public interface IContract
{
void DoWork();
}
public class BaseContract: IContract
{
public virtual void DoWork()
{
//perform operation A
}
}
现在,如果您想声明新的 EnhancedContract 类,您可以根据要求从 BaseContract 或 IContract 派生它。 如果你想对base的操作A做额外的操作,你可以从BaseContract继承它,如下所示。
public class EnhancedContract: BaseContract
{
public override void DoWork()
{
//perform operation B
base.DoWork();
//perform operation C
}
}
但是如果你对EnhancedContract的DoWork方法中的操作A不感兴趣,那么从IContract继承它。
这确保了 EnhancedWork 将执行 DoWork(),但不能保证在其中执行“操作 A”。
public class EnhancedWork:IContract
{
public void DoWork()
{
//perform operation D
}
}
这对于理解很重要,因为它会阻止用户进行以下投射。
EnhancedContract e = new EnhancedContract();
BaseContract b = e;
我相信所有这些操作在理解Open Closed principle、Liskov substitution principle时都很重要。
继承的拇指规则是“将附加功能放入现有功能中”。
【讨论】: