【问题标题】:Question about inheritance and OOP c#关于继承和OOP c#的问题
【发布时间】:2018-09-23 17:18:36
【问题描述】:

我有一个持久对象,为了这个问题,我将使用汽车 CAR 类。

public class Car
{
   public string model {get;set}
   public int year {get;set}
}

显然大大简化了。

现在,随着代码的开发,我自然而然地创建了一个接受 CAR 作为参数的函数。例如:

public void PaintCar (Car theCar)
{
  //Does some work
}

到目前为止一切顺利,但后来我有一个场景,我需要另一个类,这与 CAR 非常相似,但是 car 缺少一些字段。没问题,我认为 OOP 可以解决问题,我将直接从 Car 继承,最终得到:

public class SuperCar : Car
{
   public string newProp {get;set}
   // and some more properties
}

再一次,一切看起来都很美好,直到我遇到了一个非常有用的实用程序函数,我用它来填充 Cars 的原始属性。

Public void SetCarProperties(Car theCar)
{
    //sets the properties for car here
}

我想嗯,我希望我可以使用相同的函数来设置我的 superCar 类的属性,而无需重写。我也不想更改基本汽车定义以包含 superCar 类的所有属性。

此时我陷入了两难境地。覆盖会起作用,但它是额外的工作。有没有更优雅的解决方案。基本上我想通过超类传递给期望基类的函数。用 c# 可以吗?

我的最终代码结果是这样的:

Car myCar = new Car(); 
SetCarProperties(myCar); // ALL GOOD

SuperCar mySuperCar = new SuperCar(); 
SetCarProperties(mySuperCar); // at the moment this function is expecting type Car...

【问题讨论】:

  • 我认为在Car 类中拥有这个SetCarProperties 方法并在子类SuperCar 中覆盖它会更合适。
  • 如果不是,我认为覆盖将是最干净的解决方案。

标签: c# oop


【解决方案1】:

一个更优雅的解决方案是将函数SetCarProperties 放在Car 类中并在SuperCar 中覆盖它以使用base 来填充Car 的属性和一些额外的代码来填充SuperCar属性。

编辑:也称为多态性。

【讨论】:

  • 另外被称为非常优雅的解决方案。谢谢!
  • 您甚至可以更进一步。就像汽车不是自己建造的,而是在工厂里建造的,也许多态的建造行为也可以用同样的方式表达。例如,获得更衍生的构建器,而不是使用更衍生的汽车方法。
  • Anthony Pegram 提出的被称为工厂模式 - 你可以阅读它。然而,它有引入两个并行继承层次结构的缺点
【解决方案2】:

引入覆盖,但让原始调用基类版本来设置公共属性:

public void SetCarProperties(Car car)
{
    // set general properties
}

public void SetCarProperties(SuperCar veyron)
{
    this.SetCarProperties((Car) veyron);

    // SuperCar specific properties
}

【讨论】:

  • 你已经把层次结构颠倒过来了,Car 是这里的基类,它的方法应该被调用第二个。更重要的是,这不是多态的,所以如果你有一个 SuperCar 暴露为 Car (一旦这个 sn-p 是固定的*),它将编译为使用较少派生的方法并跳过该方法以获得更多完全派生类。
  • @Anthony Pegram:谢谢,已修复。我想我被“超级”这个词吓到了。
  • 确实,这是一种不幸的用法,尤其是如果您来自不同的背景(例如 Java)。
  • @Mark H:谢谢,但base 不起作用,因为这是课堂外的程序。我已经添加了必要的演员表。进一步的证据表明这些东西都应该分流到 Car 和 SuperCar 本身。
【解决方案3】:

你应该在 Car 类中创建一个带有 protected virtual 的方法。所以每个想要设置自己的属性的子类都可以在这个函数内部进行。所以你的代码可以如下:

   public class Car
   {
      public string model {get;set}
      public int year {get;set}

      public void SetCarProperties(Car theCar)
      {
          //sets the properties for car here
         ….
        //at the end:
          SetExtraProperties();
       }

      protected virtual void SetExtraProperties()
      {
      }

  }

在任何想要设置自己的属性的子类中,它必须将方法重写为 关注:

    public class SuperCar : Car
     {
      public string newProp {get;set}
       // and some more properties
      protected override void SetExtraProperties()
       {
       this.newProp = "";
        …
       }

     }

【讨论】:

    【解决方案4】:

    SuperCar sCar = 作为 SuperCar 的汽车; 如果(sCar!= null) { 在疤痕上设置属性; }

    在汽车上设置属性;

    【讨论】:

    • 类型检查可能会变得无法维护。每次添加新的衍生汽车时,您都必须进入此方法并对其进行更新。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-20
    • 1970-01-01
    • 1970-01-01
    • 2011-08-01
    • 1970-01-01
    相关资源
    最近更新 更多