在创建一个抽象超类之后,当你到达第一个具体的子类时,你必须实现所有的抽象方法,即使这些方法中的某些方法不会在那个具体的类中使用。所以!为什么抽象超类不会将这些抽象方法变成“假”方法,例如:
public void doThis() {
if (1 < 0){
int x = 34
}
}
它什么都不做,因为1永远不会小于0.然后当你到达具体的子类时,你不必实现所有那些抽象方法,但对于那些你想要实现的方法,你可以重写进入你需要它的方法:
public void doThis() {
//does "this".
}
两种方式都允许多态,对吗?那么我缺少抽象方法的真正优势是什么?
谢谢!
答案 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接口也需要实现或传递作为抽象到任何子类(Appender
和close
)。
现在,如果你想编写自己的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
的实现。另请注意,通过将String
和append
方法声明为final,close
禁止任何implmementation覆盖这些方法。 WebServiceAppender
方法仍然可以覆盖。
从抽象类继承的类的另一个很酷的特性是使用requireLayout
。将其视为父类“super
。在TweetAppender的情况下,requiresLayout方法的实现决定基本上推迟决定这个appender是否需要布局的责任,只需使用父类。
所以把它们放在一起:
this
无论如何,我的两分钱。
答案 4 :(得分:0)
这取决于您首先需要抽象方法的原因。例如,模板方法设计模式要求抽象方法返回值。显然,编译器无法猜出你想要返回的值。