来自其父

时间:2017-05-12 17:40:00

标签: 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 { // child
    public override void Initialize () {
        base.Initialize ();
        flies = true;
    }
}

public class Jet : Airplane { // grandchild
    public override void Initialize () {
        base.Initialize ();
        maxSpeed = 400f;
    }
}

现在,如果我实例化一个Jet对象,它将运行Vehicle初始化,但不是飞机父代码(意味着它不会飞)。

这有一些解决方法。一个是将飞机代码移动到每个子类,但它失败了使用OOP的目的。解决这个问题的最佳做法是什么?

注意:我不能使用构造函数,因为这是一个Unity3D应用程序,并且附加到GameObject的所有类都应该继承自MonoBehaviour类,并且它有自己的初始化函数,如Awake()和启动(),允许构造函数。

2 个答案:

答案 0 :(得分:6)

  

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

你不这样做

问题的假设是从飞机派生的Jet需要知道飞机从车辆派生的实施细节。这是一个糟糕的假设。最佳做法是将飞机视为黑匣子(没有双关语),而不利用其实施细节的知识。

您的Initialize方法有一个合同:它初始化了一些东西。如果你想要它被调用,你可以调用它。它负责确保其不变量得到满足;让它做它的工作。

现在,在这个特定的案例中,您不能任何。你没有写一个初始化方法,你肯定不会打电话给基地。如果您想要字段初始值设定项,那么就可以编写字段初始值设定项

class Vehicle { protected bool moves = true; }
class Airplane : Vehicle { protected bool flies = true; }
class Jet : Airplane { protected double speed = 400; }

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

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();
  }
}

你去吧。 PanelWithTitle只处理重新绘制标题,并将其余工作推迟到Panel。 Panel重新绘制面板背景,并将其余工作推迟到ControlWithChildren。 PanelWithTitle无需了解ControlWithChildren的重绘语义。如果它确实需要知道,那么 Panel 的实现就会出现问题。

答案 1 :(得分:-2)

我会创建接口并远离继承。改用构图。换句话说,make Jet包含Airplane和Vehicle类(我假设Jet具有飞机没有的特殊能力或属性)。并使用委托方法。

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

这并不是要破坏OOP的目的,而是更好的使用方式。我们仍然有那些单独的对象,而不是复制粘贴代码。但是,我们正在取消继承的使用。

我建议你阅读这篇以星球大战为主题的娱乐博客文章。 * http://blog.berniesumption.com/software/inheritance-is-evil-and-must-be-destroyed/

如果那不是你的事情只是谷歌“构成过继承”并享受火焰战争。