1

刚刚在我正在阅读的一本关于 OOP 的书中看到这句话,

只允许孩子增加功能和添加功能。永远不允许孩子删除功能。如果您确实发现子项需要删除功能,这表明子项应该在继承层次结构中出现在父项之前!

但我的问题是,这不是压倒一切吗?

4

6 回答 6

4

您可以通过覆盖删除功能。但通常你用它来改变行为。让班级按应有的方式行事。

如果行为被删除,那么它通常是一个糟糕的类设计的标志。

于 2008-11-28T21:13:40.390 回答
3

孩子不能删除功能——它可以改变它,但你不能,比如说,将公共方法设为私有。

继承的重点是您可以像处理父级一样处理子级。如果您有一个“Person”超类和一个“Employee”子类,那么 Employee 类没有 Breath() 方法是没有意义的。

于 2008-11-28T21:15:21.307 回答
1

覆盖方法时,可以在覆盖期间的某个时刻调用父实现,因此使用覆盖向父实现添加功能。

于 2008-11-28T21:14:16.753 回答
1

不。实际上你会增加功能(以消极的方式)

假设您的新功能是“什么都不做”,但方法是,您的代码的客户端看到的仍然是相同的界面

您不能拥有删除其父方法的子类。

这个有可能

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
     }
 }
于 2008-11-28T21:19:34.620 回答
0

这就是为什么重写(通常是任何虚拟成员)应该非常小心地完成的原因......事实上,通常,在重写时,您应该尝试同时编写基类和派生类,以便派生类实现首先调用基实现,然后执行它的附加功能......

但是这个原则并没有在 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 类......当他们第一次尝试使用新的基类时。

于 2008-11-28T21:15:21.727 回答
0

如果您的孩子需要删除父级的功能,则必须将父级声明为接口。因为接口是定义必须由其实现者遵守的契约的机制。

例如


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 原则Liskov 替换原则时都很重要。

继承的经验法则是“将附加功能放入现有功能中”。

于 2010-03-24T09:15:44.120 回答