Java 如果我们可以使用空的具体方法,为什么还要强迫自己在具体的子类中实现抽象方法呢?
在创建一个抽象超类之后,当您到达第一个具体的子类时,您必须实现所有的抽象方法,即使其中的一些方法不会在该具体类中使用。所以为什么抽象超类不把这些抽象方法变成“假”方法,比如:Java 如果我们可以使用空的具体方法,为什么还要强迫自己在具体的子类中实现抽象方法呢?,java,abstract,Java,Abstract,在创建一个抽象超类之后,当您到达第一个具体的子类时,您必须实现所有的抽象方法,即使其中的一些方法不会在该具体类中使用。所以为什么抽象超类不把这些抽象方法变成“假”方法,比如: public void doThis() { if (1 < 0){ int x = 34 } } 这两种方法都允许多态性,对吗?那么,我所缺少的抽象方法的真正优势是什么呢 谢谢 这取决于你为什么首先需要一个抽象方法。例如,模板方法设计模式要求抽象方法返回一个值。显然,编
public void doThis() {
if (1 < 0){
int x = 34
}
}
这两种方法都允许多态性,对吗?那么,我所缺少的抽象方法的真正优势是什么呢
谢谢 这取决于你为什么首先需要一个抽象方法。例如,模板方法设计模式要求抽象方法返回一个值。显然,编译器无法猜测您想要返回什么值。如果您没有实现所有抽象基类的方法,那么您的设计就有问题。这个想法是为了强制执行一个策略,即当您使用抽象类时: a) 抽象类无法实例化
和
b) 你必须“填空”抽象的东西是如何完成的——换句话说,你需要把抽象的东西具体化 我们不需要这些东西,但它使设计意图清晰明了。它减少了错误。如果我们遵循您的方法,就不会进行编译时检查以确保遵循“规则”
请注意,许多语言,如javascript,都没有“抽象”的概念,人们仍然使用javascript编写优秀的软件。抽象方法可以防止部分实现子类的错误。如果基本方法是具体的和空白的,编译器将允许您重新实现一些虚拟方法,而不是其他方法
在某些情况下,这是理想的结果。但通常不是这样。有几件事你没有考虑。有抽象类和抽象方法。抽象类不能直接实例化,也就是说,它们只是模板。抽象方法只能在abstrac类中定义,必须为空(即没有主体),但我们都知道这一切。但是,抽象类可以提供非抽象方法。一个完美的例子是Log4j的AppenderSkeleton(参见)
AppenderSkeleton
是一个抽象类。它有可以重写的具体方法,它有一个抽象方法(append
),如果要继承,则必须实现它(除非您的类也是一个抽象类),还有两个来自Appender
接口的方法,也需要实现或作为抽象传递给任何子类(close
和requireLayout
)
现在,如果您想编写自己的appender,比如说,在tweet上发布一些东西,您可以从以下开始:
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!
}
}
因此,所有关于日志记录的复杂问题(使用过滤器、设置级别、错误处理程序)远离您。您只需执行实际的日志记录,log4j将为您完成其余的工作。当然,如果您愿意,您的TweetAppender
可以覆盖其他方法。也许您需要执行特殊的错误处理,在这种情况下,您只需要覆盖setErrorHandler
现在,假设您还想为Facebook实现一个appender,另一个用于更改您在Skype上的状态。假设它们都通过Web服务公开API,以便发布状态更新、更改等。很快,您就会意识到有两件事情是类似的,比如调用Web服务等等。此外,你注意到Skype有一些格式,而Tweeer有另一种格式,还有其他格式。所以你明智地设计了一个WebServiceAppender:
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);
}
现在,您的tweetpender
看起来像
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
并返回字符串的实现。另外,请注意,通过将append
和close
方法声明为final,WebServicecAppender
禁止任何重写这些方法的实现。requireLayout
方法仍然可以被重写
继承抽象类的类的另一个很酷的特性是使用super
。将其视为父类“this
。对于TweetAppender,requiresLayout方法的实现决定了基本上推迟了通过简单使用t他是家长班的学生
因此,把所有这些放在一起:
public class YourParentClass {
public void doThis() {
if (1 < 0){
int x = 34
}
}
public class YourChildClass extends YourParentClass {
@Override
public void doThis() {
// do I want to do this, or something else?
if (iGuessIWillDoThis) {
super.doThis();
} else {
// do something else
}
}
}
公共类YourParentClass{
public void doThis(){
如果(1<0){
int x=34
}
}
公共类YourChildClass扩展了YourParentClass{
@凌驾
公开无效{
//我想做这个还是别的什么?
如果(我会做这件事){
太好了;
}否则{
//做点别的
}
}
}
>我的两分钱。
BTW,你是在谈论C++还是java?就我而言,java在界面中几乎总是比抽象基类更好的设计。@福尔马里,我不同意,它们完全不同。注意你可以将它们一起使用。接口是用来定义行为的,抽象类是为了提供一些功能。但允许以后填写最终细节。并非所有抽象类的方法都被设计为重写。
public class YourParentClass {
public void doThis() {
if (1 < 0){
int x = 34
}
}
public class YourChildClass extends YourParentClass {
@Override
public void doThis() {
// do I want to do this, or something else?
if (iGuessIWillDoThis) {
super.doThis();
} else {
// do something else
}
}
}