【问题标题】:Inheritance, Parent-Child and Overriding继承、父子和覆盖
【发布时间】:2008-11-28 21:09:30
【问题描述】:

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

一个孩子只能增强 功能和添加功能。 绝不允许儿童移除 功能。如果你确实发现一个 孩子需要删除功能, 这表明孩子 应该出现在父级之前 继承层次结构!

但我的问题是,这不是覆盖的作用吗?

【问题讨论】:

    标签: inheritance overriding parent-child


    【解决方案1】:

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

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

    【讨论】:

    • 所以在 C# 中,一切都继承自 system.object,对吗?您要么更改 system.object 中方法的行为,要么只是不使用它们,但永远不会删除它们。
    • 并非总是如此。 NullObjectPattern 呢 :)
    • C#有这种东西吗?请记住,我是初学者。在我看来,null 仍然是 something 尽管它代表了一个对象的缺失。这仍然是对某事的定义。
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

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

        你的子类不能删除其父类的方法。

        这是可能的

        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
             }
         }
        

        【讨论】:

          【解决方案5】:

          这就是为什么覆盖(以及一般来说,任何虚拟成员)应该非常小心地完成的事情...... 其实一般来说,在重写的时候,应该尽量同时编写基类和派生类,让派生类实现先调用基类实现,然后再执行它的附加功能……

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

          【讨论】:

          • 并非如此。如果孩子做了一件非常不同的事情(以状态模式为例),为什么它会首先调用基本 impl?对我来说,这听起来更像是模板模式,我认为这不是 OO 原则。可能是一种做法,但不是原则。
          • 因为编写您要覆盖其实现的基类的人可能在该类中有其他成员,这些成员取决于您已消除或修改的行为...
          • 这让我想起了这一点:tinyurl.com/DesignToInheranceOrProhibitIt 这正是您在谈论的内容。最好不要冒险并正确设计您的类以允许故意继承或以其他方式将方法标记为最终方法(您可以稍后将其设为非最终方法)
          • 对于不调用基类不是调用者的错误(而是基类的错误,因为它没有确保它总是被调用),因为正如你所说的那样,OO prog langs 不强制执行,我觉得那篇文章很有道理。 :)
          【解决方案6】:

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

          例如

          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 principleLiskov substitution principle时都很重要。

          继承的拇指规则是“将附加功能放入现有功能中”。

          【讨论】:

            猜你喜欢
            • 2021-07-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-06-29
            • 1970-01-01
            • 2017-09-21
            • 1970-01-01
            相关资源
            最近更新 更多