首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java抽象:抽象类委托抽象与具体类使用公共抽象

Java抽象:抽象类委托抽象与具体类使用公共抽象
EN

Stack Overflow用户
提问于 2019-09-01 11:58:01
回答 4查看 666关注 0票数 1

假设我正在实现一个简单的接口,比如动物。一般来说,这样做有两种方法:

  1. 在抽象类中实现接口的方法,并为任何具体实现所需的逻辑创建抽象方法。
  2. 在具体类中实现接口方法,并在具有保护访问权限的抽象类中移动公共逻辑。

我想知道如果-

  • 在设计方面,一种方式比另一种方式有任何客观的好处。
  • 是否建议在单个项目中只使用一种方式(代码可维护性/可读性)。
代码语言:javascript
复制
public interface Animal {
    void makeSound();
}
代码语言:javascript
复制
public abstract class BaseAnimal implements Animal {
    @Override
    public void makeSound() {
        //do something which is common for all implementaions
        doSomeImplementaionSpecificStuff();
    }

    public abstract void doSomeImplementaionSpecificStuff();
}

public class Dog extends BaseAnimal implements Animal {
    public void doSomeImplementationSpecificStuff(){
       //do something specific to a dog
    }
}
代码语言:javascript
复制
public abstract class BaseAnimal implements Animal {
    public void doCommonStuff() {
        //any common logic that can be shared between concrete  implementation goes here
    }
}

public class Dog extends BaseAnimal implements Animal {
    @Override
    public void makeSound() {
       doCommonStuff();
       //do something specific to a dog
    }
}
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2019-09-01 12:19:56

这两种方式并不总是可以互换的。

第一个示例为需要实现作为makeSound()方法一部分的特定方法的子类设置一个约束。

通过这种方式,可以将父类之一的子类的实现强耦合到其中一个子类。

此外,子类仍然可以是子类makeSound(),因为它不是final

因此,我只会在非常具体的场景中使用这种方法:

  • 要定义子类必须定义的工厂方法,因为父类依赖于该方法(抽象工厂)
  • 定义一个通用算法,并让子类定义该算法的某些特定部分(模板方法)。

在一般情况下,您希望使用第二个示例的代码,但通过执行BaseAnimal也是一个Animal

代码语言:javascript
复制
public abstract class BaseAnimal implements Animal {
    public void doCommonStuff() {
        //any common logic that can be shared between concrete  implementation goes here
    }
}

public class Dog extends BaseAnimal implements Animal {
    @Override
    public void makeSound() {
       doCommonStuff();
       //do something specific to a dog
    }
}

注意,在Java 8中,默认接口依赖于定义只定义公共方法的抽象类:

代码语言:javascript
复制
public interface Animal {
    void makeSound();
    default void doCommonStuff() {
            //any common logic that can be shared between concrete  implementation goes here    
}

还请注意,在抽象类的API中公开doCommonStuff()并不一定很好。客户应该能打电话吗?如果这是实现细节,您可以将其提取到支持类(AnimalDelegate)中,并通过将AnimalDelegate组合到Animal子类来支持组合而不是继承。

票数 0
EN

Stack Overflow用户

发布于 2019-09-01 12:04:32

主要区别在于,如果不希望实现父类/抽象类的所有方法,则可以将逻辑放在父类中,并创建一种默认方法。接口迫使您无论如何都要实现所有的方法。

代码语言:javascript
复制
public abstract class BaseAnimal {
    public void doCommonStuff() {
        System.out.println("doComon1");
    }
    public void doCommonStuff2() {
        System.out.println("doComon1");
    }

    public static void main(String[] args) {
        SuperDog superDog = new SuperDog();
        superDog.doCommonStuff();
    }
}

两项执行可以是:

代码语言:javascript
复制
public class cat extends BaseAnimal {
    @Override
    public void doCommonStuff() {
        //specific logic
    }
    @Override
    public void doCommonStuff2() {
        //specific logic
    }
}

public class Dog extends BaseAnimal {
    @Override
    public void doCommonStuff() {
        //specific logic
    }
    // don't override the doCommonStuff2() method so you have the parent implementation
}

此外,对于抽象类,您可以混合使用:

代码语言:javascript
复制
public class SuperDog extends BaseAnimal {
    @Override
    public void doCommonStuff(){
        super.doCommonStuff();
        System.out.println("do specific after common stuff");
    }
}

最后一个,可以调用父逻辑,也可以添加特定的逻辑。有了接口,您就不能这样做。

票数 0
EN

Stack Overflow用户

发布于 2019-09-01 12:06:54

如果有一种默认的通用方法来实现大多数子类将使用的接口,那么只需在抽象类中这样实现overriden方法即可。任何需要它的子类都可以保持原样。任何需要它的子类都可以完全重写和重新实现它。任何想要使用默认实现但又向其添加一些内容的子类都可以重写,然后调用super.makeSound()作为实现的一部分。

不要忘记准确地记录默认实现是什么。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57745799

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档