如果我们可以使用空的具体方法,为什么强迫自己在具体的子类中实现抽象方法呢?

时间:2011-02-10 17:38:34

标签: java abstract

在创建一个抽象超类之后,当你到达第一个具体的子类时,你必须实现所有的抽象方法,即使这些方法中的某些方法不会在那个具体的类中使用。所以!为什么抽象超类不会将这些抽象方法变成“假”方法,例如:

public void doThis() { 
     if (1 < 0){ 
          int x = 34
     }
}

它什么都不做,因为1永远不会小于0.然后当你到达具体的子类时,你不必实现所有那些抽象方法,但对于那些你想要实现的方法,你可以重写进入你需要它的方法:

public void doThis() {
      //does "this".
}

两种方式都允许多态,对吗?那么我缺少抽象方法的真正优势是什么?

谢谢!

5 个答案:

答案 0 :(得分:4)

如果您没有实现所有抽象基类的方法,那么您的设计就会出现问题。

答案 1 :(得分:2)

这个想法是强制执行一个使用抽象类的策略:

a)抽象的类无法实例化 和
b)你必须“填补空白”以了解抽象的东西是如何完成的 - 换句话说,你需要使抽象的东西具体化。

我们不需要这些东西,但它使设计意图清晰,干净。它减少了错误。如果我们按照您的方法进行操作,则不会进行编译时检查以确保遵循“规则”。

请注意,许多语言(如javascript)都没有“抽象”的概念,人们仍然使用javascript编写好的软件。

答案 2 :(得分:2)

抽象方法可以保护您免受部分实现子类的错误的影响。如果基本方法是具体而空白的,编译器将让你逃避重新实现一些虚拟,而不是其他虚拟。

有些情况下,这是理想的结果。但通常情况并非如此。

答案 3 :(得分:1)

有几件事你没有考虑。有抽象类和抽象方法。抽象类不能直接实例化,它们只是模板。抽象方法只能在abstrac类中定义,必须为空(即没有正文),但我们知道这一切。但是,抽象类可以提供非抽象方法。一个完美的例子是Log4j的AppenderSkeleton(见http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/AppenderSkeleton.html)。

AppenderSkeleton是一个抽象类。它有你可以覆盖的具体方法,它有一个抽象方法(append),如果你继承你必须实现(除非你的类也是一个抽象类),并且有两个方法来自{{1接口也需要实现或传递作为抽象到任何子类(Appenderclose)。

现在,如果你想编写自己的appender,比方说,推特一些东西,你可以从:

开始
requireLayout

因此,所有关于日志记录(使用过滤器,设置级别,错误处理程序)的复杂性都远离您。您只需要进行实际的日志记录,log4j将为您完成剩下的工作。当然,如果您愿意,您的public class TweetAppender extends AppenderSkeleton { public boolean requiresLayout() { return false; } public void close() { // do nothing } @Override protected void append(LoggingEvent event) { // take the message and tweet it! } } 可以覆盖其他方法。也许您想要进行特殊的错误处理,在这种情况下,您只需要覆盖TweetAppender

现在,想象一下你也希望为Facebook实现一个appender,另一个用来改变你在Skype上的状态。假设他们都通过Web服务公开API,以便发布状态更新,更改等。很快您就会意识到有一些类似的东西,比如调用Web服务,等等。另外,你注意到Skype有一些格式,而Tweeter有另一种格式,什么不是。所以你明智地做了一个WebServiceAppender:

setErrorHandler

现在,您的public abstract class WebServiceAppender extends AppenderSkeleton { public boolean requiresLayout() { return false; } public final void close() { // do extra clean up of resources } // make this final so no one can do strange stuff protected final void append(LoggingEvent event) { // do a lot of stuff, like, opening up a connection // send an xml, close the connection and stuff... // ... // ready to send the message! final String messageToSend = getFormattedMessage(event); // send the message and do lots of complicated stuff // ... // close and clean up } // let the implementations decide on the format protected abstract String getFormattedMessage(LoggingEvent event); } 看起来像

TweetAppender

通过将public class TweetAppender extends WebServiceAppender { @Override protected String getFormattedMessage(LoggingEvent event) { // use tweeter's specific format } public boolean requiresLayout() { return super.requiresLayout(); } } 声明为抽象,getFormattedMessage强制任何实现实际提供一个实现WebServiceAppender并返回LoggingEvent的实现。另请注意,通过将Stringappend方法声明为final,close禁止任何implmementation覆盖这些方法。 WebServiceAppender方法仍然可以覆盖。

从抽象类继承的类的另一个很酷的特性是使用requireLayout。将其视为父类“super。在TweetAppender的情况下,requiresLayout方法的实现决定基本上推迟决定这个appender是否需要布局的责任,只需使用父类。

所以把它们放在一起:

this

无论如何,我的两分钱。

答案 4 :(得分:0)

这取决于您首先需要抽象方法的原因。例如,模板方法设计模式要求抽象方法返回值。显然,编译器无法猜出你想要返回的值。