【问题标题】:Write a method implementation in base class which requires override in subclasses?在基类中编写需要在子类中覆盖的方法实现?
【发布时间】:2011-11-13 20:26:11
【问题描述】:

在 Java 中...

我正在创建一个包含方法 doAction() 的类 Foo。我的要求:

  1. doAction() 在 Foo 中必须有一个默认实现(即函数体)。
  2. Foo 的所有子类都必须覆盖 doAction(),这意味着如果子类不提供新的实现,它们将获得编译器错误。
  3. 我需要能够实例化 Foo。

abstract 可以,但它不允许我为 doAction() 指定函数体。

【问题讨论】:

  • 吃蛋糕还是吃蛋糕;不能两者兼得……
  • 为什么必须 doAction()有一个默认实现,如果它只是被子类忽略?
  • 我需要自己运行/测试基类。
  • @frankadelic 我不建议在基类中添加专门用于测试的代码。这是不好的做法,会让未来的开发人员感到困惑,而且很难维护。你需要的是一个像 Rhino Mocks 这样的 Mocking 框架,为了测试目的,你可以指定你想要返回的内容。

标签: java oop inheritance overriding


【解决方案1】:

编辑

不可能同时满足所有要求,故事结束。您必须至少放弃一个条件,并且可能考虑一种完全不同的方法来解决您要解决的问题。


使用两种不同的方法。要么:

abstract class Foo {
    
    // Override this method
    abstract void doActionInSubclass();
    
    // You can't override a final method
    // And you don't want subclases to override this one
    final void doAction () {
        // do whatever default-y things you want here
        doActionInSubclass();
    }
}

或者只是将“必需”方法与您想要强制子类覆盖的方法完全分开:

abstract class Foo {
    abstract void mustOverrideThisInConcreteSubclasses();
    
    final void doAction() {
        // default-y things here
    }
}

【讨论】:

  • 这个解决方案的问题是我无法实例化 Foo。我将更新我的问题以澄清此要求。
  • 不可能同时满足所有要求,故事结束。
  • 如果您希望实例化抽象类只是为了测试默认方法,即具体方法,您可以(在您的测试源代码中)创建一个TestFoo extends Foo,然后测试 那个.
【解决方案2】:

如果在 Java 中为方法提供默认实现,则不能强制子类再次覆盖它。如果可以,请使用 template method 模式并使用不同的方法名称:

public class Foo{

    public abstract void templateMethod();
    public final void doAction(){

    //default implementation

     templateMethod(); // call template method
    }
}

【讨论】:

  • doAction() 应该是最终的,因为有人可以在子类中重新定义它。
【解决方案3】:

Foo 中实现您的方法并使其始终抛出异常,例如UnsupportedOperationException。这将要求子类覆盖该方法。

【讨论】:

  • 并且用户可以捕获异常使程序继续运行。
  • 他希望该方法具有默认实现,而不是抛出异常。
【解决方案4】:

如果所有子类都应该覆盖它,为什么要提供默认实现?!这将毫无意义,因为没有人会使用它。但是,您可能有一些您希望由任何子类执行的 doAction 代码和一些您希望被覆盖的代码。 在这种情况下,您可以设计如下:

doAction(){
     //put your default code here...
     specificAction();
}

abstract specificAction();

通过这种方式,doAction 有自己的实现,它由特定的Action 调用结束,而应该由子类来实现

【讨论】:

  • 如您所见,您的问题有很多类似的答案:)
【解决方案5】:

Foo 类的构造函数中,您可以使用reflection

class Foo {
    public Foo() {
        Class c = getClass();
        if (!c.equals(Foo.class))
        {
            // try/catch omitted for brevity
            Method m = c.getMethod("methodName", new Class[0]);
            if (m.getDeclaringClass().equals(Foo.class))
            {
                throw new Exception("blah blah blah");
            }
        }
    }
}

这不会产生编译时错误,但由于在构造函数中对 super() 的调用不能用 try 包装,因此任何创建子类的人都无法绕过它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 2012-12-04
    • 2017-06-07
    • 1970-01-01
    • 2012-07-22
    • 2011-11-03
    • 2012-11-15
    相关资源
    最近更新 更多