Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/265.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 孙子类从其父类调用方法的最佳OOP实践_C#_Oop - Fatal编程技术网

C# 孙子类从其父类调用方法的最佳OOP实践

C# 孙子类从其父类调用方法的最佳OOP实践,c#,oop,C#,Oop,我想知道构造类的最佳实践,以便在类有祖辈时调用父方法 假设我有这样一个场景: public class Vehicle { // parent public bool moves; public bool flies; public float maxSpeed; public virtual void Initialize () { moves = true; } } public class Airplane : Vehicle

我想知道构造类的最佳实践,以便在类有祖辈时调用父方法

假设我有这样一个场景:

public class Vehicle { // parent

    public bool moves;
    public bool flies;
    public float maxSpeed;

    public virtual void Initialize () {
        moves = true;
    }
}

public class Airplane : Vehicle { // child
    public override void Initialize () {
        base.Initialize ();
        flies = true;
    }
}

public class Jet : Airplane { // grandchild
    public override void Initialize () {
        base.Initialize ();
        maxSpeed = 400f;
    }
}
现在,如果我实例化一个Jet对象,它将运行车辆初始化,但不运行飞机父代码(意味着它不会飞行)

有一些解决办法。一种是将飞机代码移动到每个子类,但这样做会破坏使用OOP的目的。解决这个问题的最佳做法是什么


注意:我不能使用构造函数,因为这是一个Unity3D应用程序,连接到游戏对象的所有类都应该继承自MonoBehavior类,它有自己的初始化函数,如Awake()和Start(),并且不允许构造函数。

我会创建接口,远离继承。用构图代替。换句话说,makejet包含飞机和车辆两个类(我假设一架飞机有飞机没有的特殊能力或属性)。并使用委托人方法

它使您的项目不那么脆弱。换句话说,如果你改变你的基类,你必须担心你的孩子(甚至是曾孙)是如何处理的。但是,如果包含它,只要接口相同,容器类就不会在意

这不是违背OOP的目的,而是更好的使用方法。我们仍然有这些独立的对象,并且不是复制粘贴代码。然而,我们正在阻止继承的使用

我建议你阅读这篇以星球大战为主题的娱乐性博客文章。 *

如果这不是你的事,那就用谷歌搜索“合成重于继承”,享受火焰之战吧

我想知道构造类的最佳实践,以便在类有祖辈时调用父方法

您不能这样做

问题的假设是,从飞机衍生的喷气式飞机需要知道飞机从车辆衍生的实现细节。那是个错误的假设。最佳实践是将飞机视为一个黑匣子(没有双关语),而不利用对其实现细节的了解

Initialize方法有一个约定:它初始化某些内容。如果你想叫它,就叫它。它负责确保满足其不变量;让它做它的工作

现在,在这种特殊情况下,你不需要做任何事情。您没有编写初始化方法,当然也没有调用基。如果需要字段初始值设定项,则需要编写字段初始值设定项

让我们考虑一个更好的例子。假设我们有一个可以重新绘制的显示曲面:

interface IUserInterface { void Redraw(); }
现在我们可以提出一个层次结构,其中的规则是:重画时,还必须调用超类:

abstract class ControlWithChildren : IUserInterface
{
  ...
  protected IEnumerable<IUserInterface> children;
  public virtual void Redraw() { 
    foreach(var child in children) child.Redraw();
}

class Panel : ControlWithChildren
{
  ...
  public override void Redraw()
  {
    ... redraw panel elements ...
    base.Redraw();
  }
}

class PanelWithTitle : Panel
{
  ...
  public override void Redraw()
  {
    ... redraw title element ...
    base.Redraw();
  }
}
带子对象的抽象类控件:IUserInterface
{
...
受保护的无数儿童;
公共虚拟空重绘(){
foreach(children中的var child)child.Redraw();
}
类面板:带孩子的控件
{
...
公共覆盖无效重绘()
{
…重新绘制面板元素。。。
base.Redraw();
}
}
类别PanelWithTitle:Panel
{
...
公共覆盖无效重绘()
{
…重新绘制标题元素。。。
base.Redraw();
}
}

好了。PanelWithTitle只处理重画标题的问题,并将其余工作推迟到Panel。Panel重画面板背景,并将其余工作推迟到ControlWithChildren。PanelWithTitle不需要了解ControlWithChildren的重画语义。。如果它确实需要知道这一点,那么面板的实现有问题。

什么是构造函数?@EdPlunkett您可以在此处了解有关构造函数的更多信息:p@RufusL如果网络上有一些资源可以自动回答这样的问题就好了。如果这些代码是以一种无需手动编辑即可编译的方式编写的,那就太好了。否代码中的东西很有道理。为什么使用初始化方法而不是构造函数?为什么初始值设定项是私有的?为什么它们不是虚拟的?为什么你相信Jet对象不会调用基方法?为什么字段初始值设定项不是字段初始值设定项?我不能理解这个问题的头绪。飞机包含一个飞行器?这是一架货机吗?“我假设一架喷气式飞机具有飞机所不具备的特殊能力或特性”。它有一个喷气发动机。你不理解合成的概念。你在建模一个有关系而不是有关系时使用合成。此外,你不只是扔掉继承,而是与合成一起使用。飞机是一辆交通工具,喷气机是一架飞机。在一个正确合成的类中,你仍然会有一辆交通工具d飞机,但飞机只是定义了组成飞机的部件组成,所以飞机只需更换部件组成。但是如果飞机比飞机有更多的功能,你就需要创建一个新类。你链接中的家伙甚至显示了这一点。我想你误读了他的问题。他问如何调用
父方法问题是,父方法被跳过,祖父母被调用。至少我认为他是这么说的。@RufusL:当然,他这么说,没有证据,也没有编译或运行的代码。问题是:在一个有大基的世界里,调用基方法的最佳实践是什么,这个问题表明了这一点对于类与其grandbase之间的关系,可能存在一种不好的心态。这里更重要的不是OP修复了未显示的错误代码中的打字错误。最重要的是他们开始正确思考类型层次结构。
abstract class ControlWithChildren : IUserInterface
{
  ...
  protected IEnumerable<IUserInterface> children;
  public virtual void Redraw() { 
    foreach(var child in children) child.Redraw();
}

class Panel : ControlWithChildren
{
  ...
  public override void Redraw()
  {
    ... redraw panel elements ...
    base.Redraw();
  }
}

class PanelWithTitle : Panel
{
  ...
  public override void Redraw()
  {
    ... redraw title element ...
    base.Redraw();
  }
}