【问题标题】:How to declare abstract method in non-abstract class如何在非抽象类中声明抽象方法
【发布时间】:2016-05-10 02:28:18
【问题描述】:

我想声明几个抽象方法(因此在继承自该方法的类中需要实现)以适应我的情况,即:

我正在制作一个解谜程序。到目前为止,我有 3 个包:

  • games.puzzles
  • games.puzzles.rivercrossing
  • games.puzzles.rivercrossing.wolfgoatcabbage

我不想太具体,但在 games.puzzles.rivercrossing 包中,我有两个代表银行和州的类:GenericBankGenericState

现在,它们定义了一些行为,但是从这些继承的类必须具有一些方法,例如move() 将一个元素从一个银行移动到另一个银行或isPermitted()isFinal() 检查状态。

例如,在最后一个包中,我有 WolfGoatCabbageGame 类,它必须有自己的 BankState 类,它们将从通用类继承。这些特定的BankState 类必须实现我上面提到的方法,例如在狼、山羊和卷心菜游戏中,检查山羊和狼是否不在同一个银行等。

所以最初我将泛型类声明为abstract,这些方法也将被实现abstract

public abstract class GenericBank {
    // more members ...
    public abstract boolean move(Element element, GenericBank dst);
    // more members...  
}

public abstract class GenericState {
    // more members... 
    public abstract boolean isPermitted(GenericBank bank);

    public abstract boolean isFinal(GenericBank bank);
    // more members... 
}

在我发现我必须实例化 GenericBankGenericState 对象之前,这看起来是可行的,如果这些类是抽象的,当然不能这样做。

所以我不得不从类中删除 abstract 限定符。

那么……我该怎么办?如何在非abstract 类中声明abstract 方法(或实现相同的行为)?

【问题讨论】:

  • 为什么需要实例化GenericBankGenericState
  • 生成抽象类的对象是没有意义的,因为它没有所有的实现。考虑使用接口来解决您的问题。
  • 一个简单的解决方案是在Generic...classes 中使用空主体(即默认行为是“什么都不做”)实现这些方法,并在子类中覆盖这些方法
  • 你的课程设计得很糟糕。在设计良好的系统中,不需要实例化具有abstract 方法的类。你在这里问错了问题。
  • 我真的没有得到反对票。你可以说“嘿,实例化一个抽象类没有意义”或“嘿,你应该重新考虑你的类层次结构”或“嘿,这是我建议你应该做的”。但是不,让我们用反对票炒掉这个家伙,因为我可以。这就是为什么外面这么多人鄙视这个网站的原因。一些模组删除了这个问题,因为它对任何人没有帮助。

标签: java oop inheritance


【解决方案1】:

您可以改用虚拟

internal class ClassA
{
    public void Print()
    {
        Console.WriteLine("A");
        PrintVirtual();
        Console.WriteLine("--------------------------------------------------");
    }
    protected virtual void PrintVirtual()
    {
        Console.WriteLine("Virtual");
    }
}

internal class ClassB : ClassA
{
    protected override void PrintVirtual()
    {
        Console.WriteLine("B");
    }
}

internal class ClassC : ClassA
{
    protected override void PrintVirtual()
    {
        Console.WriteLine("C");
        base.PrintVirtual();
    }
}

然后你就可以运行测试了

new ClassA().Print();
new ClassB().Print();
new ClassC().Print();

【讨论】:

    【解决方案2】:

    你不能,抽象类的定义就是它有抽象方法。

    您可以做的是定义可以被子类否决的默认行为。

    但是,在执行此操作之前,我会仔细考虑您的类层次结构。您需要在某些类的实际实现已知之前对其进行实例化这一事实表明您的设计可能需要重新考虑。

    如果您要重新设计,您将需要查看实例化的时间 - 以及在此基础上进行实例化的原因。
    现在,您想在知道该类的实际实例之前使用该类的一些常见行为。

    这有点超出了回答问题的范围,但是:考虑向朋友解释代码的设计。或发送至rubber duck。这可能会帮助您找到新的方法。

    【讨论】:

    • 但这正是我不想做的。没有默认行为。这些方法仅在子类(即实际游戏)中才有意义。
    • @dabadaba 那恐怕你得回到白板了。看看你是否可以重新安排一些事情,以便在知道它们的具体实现之前不需要实例化这些类。
    • 但问题是定义了一个共同的行为。只是某些方法由子类定义,从不由父类定义。
    • @dabadaba 如果我理解正确的问题,它是关于实例化时间。您仍然可以拥有一个类层次结构,其中一个超类定义了常见行为。但是您必须重构代码,使这些类在它们的具体实现已知之前不实例化
    【解决方案3】:

    您可以将抽象方法替换为不执行任何操作并返回其各自返回类型的默认值的空方法(如有必要,使其成为泛型类协定的一部分,子类必须覆盖这些方法)。

    或者,您可以保留您的抽象 Generic*-classes 并在 Null object pattern 之后添加具有上述空实现的 Null*-classes。

    【讨论】:

    • 这正是我想要避免的。留下一个空的身体或返回一些随机的东西似乎......错了。
    • 这就是我建议空对象的原因,因此您可以将抽象方法留在泛型类中。但是由于您没有告诉我们为什么需要实例化泛型类,因此每个建议都只是一个疯狂的猜测
    【解决方案4】:

    删除抽象限定符并添加一个空主体,或者抛出一些运行时异常。

    或者将这些泛型类实例化为匿名子类

    【讨论】:

      【解决方案5】:

      如何在非抽象类中声明抽象方法?

      回答:你不能。这是一种抽象的定义。这与你不能将对象实例化为抽象类的原因相同。

      要么:

      A) 你需要使用接口

      B) 将父类中的方法留空:

      //technically this needs to return a value, but it doesn't need to *do* anything
      public boolean isPermitted(GenericBank bank){ return false; }
      

      C) 重构您的代码,这样您就不会实例化抽象对象。我无法建议如何执行此操作,因为您尚未提供任何相关代码。

      【讨论】:

      • 使用接口没有意义,因为我必须为其他方法实现默认行为。留下空的身体似乎是错误的。所以我最终重构了我的代码。无需在另一个类的构造函数中实例化抽象类,只需将其直接分配给成员变量,并且它已经在其他允许的地方实例化了。
      • 对于您的解决方案 B,我认为它需要是虚拟的,并且它也可以抛出未实现的异常。 virtual 允许派生类型覆盖它并抛出异常确保它会被实现。
      【解决方案6】:

      您不能在非抽象类中声明 abstract 方法,最后一个点。

      那只会玷污abstract 方法的概念。

      可以做的是让您的类层次结构实现接口,指示实现所需的方法。

      如果您发现以前的 abstract 类实际上设计为具体类更好,请将它们转换为具体类并实现方法,即使使用默认的通用实现也是如此。

      然后您可以微调子类中的覆盖。

      【讨论】:

        猜你喜欢
        • 2011-01-23
        • 1970-01-01
        • 1970-01-01
        • 2012-09-21
        • 2012-09-16
        • 1970-01-01
        • 2014-02-26
        • 2015-02-28
        • 2012-10-31
        相关资源
        最近更新 更多