在基类中编写需要在子类中覆盖的方法实现?
Posted
技术标签:
【中文标题】在基类中编写需要在子类中覆盖的方法实现?【英文标题】:Write a method implementation in base class which requires override in subclasses? 【发布时间】:2011-11-13 20:26:11 【问题描述】:在 Java 中...
我正在创建一个包含方法 doAction() 的类 Foo。我的要求:
-
doAction() 在 Foo 中必须有一个默认实现(即函数体)。
Foo 的所有子类都必须覆盖 doAction(),这意味着如果子类不提供新的实现,它们将获得编译器错误。
我需要能够实例化 Foo。
abstract 可以,但它不允许我为 doAction() 指定函数体。
【问题讨论】:
吃蛋糕还是吃蛋糕;不能两者兼得…… 为什么必须doAction()
有一个默认实现,如果它只是被子类忽略?
我需要自己运行/测试基类。
@frankadelic 我不建议在基类中添加专门用于测试的代码。这是不好的做法,会让未来的开发人员感到困惑,而且很难维护。你需要的是一个像 Rhino Mocks 这样的 Mocking 框架,为了测试目的,你可以指定你想要返回的内容。
【参考方案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
包装,因此任何创建子类的人都无法绕过它。
【讨论】:
以上是关于在基类中编写需要在子类中覆盖的方法实现?的主要内容,如果未能解决你的问题,请参考以下文章