Java 接口不考虑来自 super class 的方法实现
Java Interface does not take into consideration method implementation from the super class
以下鸭子示例基于 Head First 设计模式一书。
我有一个游戏,有不同类型的鸭子。有一只超级class Duck,它有两种行为:fly 和quack,存储在字段中。具体 classes 决定(在构造函数中)具体品种具有哪种行为(参见 MalardDuck class)。
我意识到我希望我的鸭子不仅具有 Duck 类型,而且还具有 Quackable 类型(这样我就可以拥有只接受嘎嘎类型的方法 - 假设还有其他类型的嘎嘎 - 请参阅 Lake class)。当我在 MallardDuck 中实现接口时,编译器抱怨 class 没有 quack 方法,尽管它在其 superclass - Duck class.
中定义
现在我想到了两个解决方案:
- 通过从 superclass 调用方法来覆盖方法 quack: super.quack() <- 但这似乎是不必要的(理论上)- a child class 可以直接访问 superclass 的 public 方法,那么为什么接口 Quackable 甚至抱怨...?
- 让 Duck 实现 Quackable -> 这是相当不合逻辑的,因为有些 Ducks 不嘎嘎(它们的 quackBehaviour 是用 SiletnQuack class 实现的)。
但是在这两种解决方案中,鸭子:
- 有嘎嘎作响的行为,并且
- 是个嘎嘎嘎嘎的
这不是根本错误吗?我错过了什么?
abstract class Duck{
protected Flyiable flyBehaviour;
protected Quackable quackBehaviour;
public void quack(){
quackBehaviour.quack();
}
void performFly(){
flyBehaviour.fly();
}
void swim(){
// swimming implementation
}
abstract void display();
}
interface Quackable{
void quack();
}
class Quack implements Quackable{
@Override
public void quack() {
System.out.println("Quack!");
}
}
class Quack implements Quackable{
@Override
public void quack() {
System.out.println("Quack!");
}
}
class SilentQuack implements Quackable{
@Override
public void quack() {
System.out.println("...");
}
}
class MallardDuck extends Duck{
public MallardDuck(){
quackBehaviour = new Quack();
flyBehaviour = new FlyWithWings();
}
@Override
void display() {
// it looks like a Mallard duck
}
}
如果我想接受这种方法的鸭子作为嘎嘎(以及其他动物)怎么办:
class Lake{
ArrayList<Quackable> quackingAnimals;
void addQuackingAnimal(Quackable animal){
quackingAnimals.add(animal);
}
void displayQuackables(){
//...
}
}
解决方案 1:
class MallardDuck extends Duck implements Quackable {
public MallardDuck(){
quackBehaviour = new Quack();
flyBehaviour = new FlyWithWings();
}
@Override
void display() {
// it looks like a Mallard duck
}
@Override
public void quack() {
super.quack();
}
}
解决方案 2:
abstract class Duck implements Quackable{
protected Flyiable flyBehaviour;
protected Quackable quackBehaviour;
public void quack(){
quackBehaviour.quack();
}
void performFly(){
flyBehaviour.fly();
}
void swim(){
// swimming implementation
}
abstract void display();
}
这是因为 Duck
class 没有实现 Quackable
接口中的 quack
方法。虽然它有一个具有相同签名的 quack
方法,但它不是在接口中声明的相同方法。
我不明白,为什么解决方案 2(使 Duck
class 实现 Quackable
接口)是不合逻辑的 - 它确实暴露了 public 嘎嘎的方法,所以它的所有后代无论如何都会 quack
(但是在 Quackable
接口中声明的 quack
不同)。在我看来(唯一的意见),Duck
class 应该实现 Quackable
.
如果(在你的情况下)不是所有 Ducks
quack
,那么 Duck
不能被视为具有 Quackable
的东西是合理的行为,因此无法将其添加到 Quackable
个对象的集合中。在这种情况下(在我看来)你可以创建另一个抽象 class 扩展 Duck
并实现 Quackable
接口(如 QuackingDuck
),在这种情况下(在我看来)你应该从 Duck
class 中删除 quack
方法 - 因为并非所有 Ducks
quack
.
我希望它能回答您的问题。总结:
Duck
中的 quack
方法不是 Quackable
接口中 quack
方法的实现(例如 [=61= 中的情况) ])
- 在当前的实现中,所有
Ducks
quack
,只有它们的 quacking
行为(实现)不同(并且在 SilentDuck
的情况下 - 它仍然 quacks
)
[在你的问题中,我更喜欢使用“委托”一词而不是“行为”,因为我个人认为它更能表达这个概念。]
您的界面 Quackable
实际上意味着“可以嘎嘎叫的东西”。
甚至原始的 Duck
抽象 class 也有那个方法,所以它已经遵循那个接口,但是你“忘记”声明了那个事实。在一致的世界中,您应该 Duck
从一开始就实施 Quackable
。
关于 HAS 和 IS:
所有 Ducks
都有一些 quack()
方法,因此实际上它们是 Quackable
(意思是“可以嘎嘎叫的东西”)。他们如何决定他们的 quack() 实现、使用继承的委托方法、通过提供不同的 delegete/behaviour 修改继承的版本或覆盖该方法都无关紧要。
他们拥有 quack()
能力这一事实将他们定义为 Quackable
。
你的 Duck subclasses 也有一个 Quackable
并将其用作代表,将真正的嘎嘎声推迟到其他一些“行为”实例(比如不发表意见的政客他自己,而是通过代言人)。
因此,class 同时成为 Quackable
和拥有 Quackable
并没有错。在现实世界中,我们都是 LivingCreatures,我们中的许多人都将 LivingCreatures 作为我们的宠物。
关于行为对象的备注:
尽管此模式可能很有用,但请注意,您失去了使 quack()
行为取决于鸭子状态的能力(或至少使其相当复杂)(例如,如果在水上或在空中)。
您在 superclass 和接口中使用相同的方法。 MallardDuck 中的 quack()
方法 class 一次做 2 件事:
- 在 superclass Duck
中覆盖 quack()
- 在 Quackable 接口中实现
quack()
。
解决方案 2 可帮助您避免这种情况。
以下鸭子示例基于 Head First 设计模式一书。
我有一个游戏,有不同类型的鸭子。有一只超级class Duck,它有两种行为:fly 和quack,存储在字段中。具体 classes 决定(在构造函数中)具体品种具有哪种行为(参见 MalardDuck class)。
我意识到我希望我的鸭子不仅具有 Duck 类型,而且还具有 Quackable 类型(这样我就可以拥有只接受嘎嘎类型的方法 - 假设还有其他类型的嘎嘎 - 请参阅 Lake class)。当我在 MallardDuck 中实现接口时,编译器抱怨 class 没有 quack 方法,尽管它在其 superclass - Duck class.
中定义现在我想到了两个解决方案:
- 通过从 superclass 调用方法来覆盖方法 quack: super.quack() <- 但这似乎是不必要的(理论上)- a child class 可以直接访问 superclass 的 public 方法,那么为什么接口 Quackable 甚至抱怨...?
- 让 Duck 实现 Quackable -> 这是相当不合逻辑的,因为有些 Ducks 不嘎嘎(它们的 quackBehaviour 是用 SiletnQuack class 实现的)。
但是在这两种解决方案中,鸭子:
- 有嘎嘎作响的行为,并且
- 是个嘎嘎嘎嘎的
这不是根本错误吗?我错过了什么?
abstract class Duck{
protected Flyiable flyBehaviour;
protected Quackable quackBehaviour;
public void quack(){
quackBehaviour.quack();
}
void performFly(){
flyBehaviour.fly();
}
void swim(){
// swimming implementation
}
abstract void display();
}
interface Quackable{
void quack();
}
class Quack implements Quackable{
@Override
public void quack() {
System.out.println("Quack!");
}
}
class Quack implements Quackable{
@Override
public void quack() {
System.out.println("Quack!");
}
}
class SilentQuack implements Quackable{
@Override
public void quack() {
System.out.println("...");
}
}
class MallardDuck extends Duck{
public MallardDuck(){
quackBehaviour = new Quack();
flyBehaviour = new FlyWithWings();
}
@Override
void display() {
// it looks like a Mallard duck
}
}
如果我想接受这种方法的鸭子作为嘎嘎(以及其他动物)怎么办:
class Lake{
ArrayList<Quackable> quackingAnimals;
void addQuackingAnimal(Quackable animal){
quackingAnimals.add(animal);
}
void displayQuackables(){
//...
}
}
解决方案 1:
class MallardDuck extends Duck implements Quackable {
public MallardDuck(){
quackBehaviour = new Quack();
flyBehaviour = new FlyWithWings();
}
@Override
void display() {
// it looks like a Mallard duck
}
@Override
public void quack() {
super.quack();
}
}
解决方案 2:
abstract class Duck implements Quackable{
protected Flyiable flyBehaviour;
protected Quackable quackBehaviour;
public void quack(){
quackBehaviour.quack();
}
void performFly(){
flyBehaviour.fly();
}
void swim(){
// swimming implementation
}
abstract void display();
}
这是因为 Duck
class 没有实现 Quackable
接口中的 quack
方法。虽然它有一个具有相同签名的 quack
方法,但它不是在接口中声明的相同方法。
我不明白,为什么解决方案 2(使 Duck
class 实现 Quackable
接口)是不合逻辑的 - 它确实暴露了 public 嘎嘎的方法,所以它的所有后代无论如何都会 quack
(但是在 Quackable
接口中声明的 quack
不同)。在我看来(唯一的意见),Duck
class 应该实现 Quackable
.
如果(在你的情况下)不是所有 Ducks
quack
,那么 Duck
不能被视为具有 Quackable
的东西是合理的行为,因此无法将其添加到 Quackable
个对象的集合中。在这种情况下(在我看来)你可以创建另一个抽象 class 扩展 Duck
并实现 Quackable
接口(如 QuackingDuck
),在这种情况下(在我看来)你应该从 Duck
class 中删除 quack
方法 - 因为并非所有 Ducks
quack
.
我希望它能回答您的问题。总结:
Duck
中的quack
方法不是Quackable
接口中quack
方法的实现(例如 [=61= 中的情况) ])- 在当前的实现中,所有
Ducks
quack
,只有它们的quacking
行为(实现)不同(并且在SilentDuck
的情况下 - 它仍然quacks
)
[在你的问题中,我更喜欢使用“委托”一词而不是“行为”,因为我个人认为它更能表达这个概念。]
您的界面 Quackable
实际上意味着“可以嘎嘎叫的东西”。
甚至原始的 Duck
抽象 class 也有那个方法,所以它已经遵循那个接口,但是你“忘记”声明了那个事实。在一致的世界中,您应该 Duck
从一开始就实施 Quackable
。
关于 HAS 和 IS:
所有 Ducks
都有一些 quack()
方法,因此实际上它们是 Quackable
(意思是“可以嘎嘎叫的东西”)。他们如何决定他们的 quack() 实现、使用继承的委托方法、通过提供不同的 delegete/behaviour 修改继承的版本或覆盖该方法都无关紧要。
他们拥有 quack()
能力这一事实将他们定义为 Quackable
。
你的 Duck subclasses 也有一个 Quackable
并将其用作代表,将真正的嘎嘎声推迟到其他一些“行为”实例(比如不发表意见的政客他自己,而是通过代言人)。
因此,class 同时成为 Quackable
和拥有 Quackable
并没有错。在现实世界中,我们都是 LivingCreatures,我们中的许多人都将 LivingCreatures 作为我们的宠物。
关于行为对象的备注:
尽管此模式可能很有用,但请注意,您失去了使 quack()
行为取决于鸭子状态的能力(或至少使其相当复杂)(例如,如果在水上或在空中)。
您在 superclass 和接口中使用相同的方法。 MallardDuck 中的 quack()
方法 class 一次做 2 件事:
- 在 superclass Duck 中覆盖
- 在 Quackable 接口中实现
quack()
。
quack()
解决方案 2 可帮助您避免这种情况。