下面的ducks示例基于head-first设计模式手册。
我和不同类型的鸭子玩游戏。这里有一只超级级的鸭子,它有两种行为:苍蝇和呱呱,它们被储存在田野里。具体类决定(在构造器中)一个具体品种的行为(参见malardduck类)。
我意识到我希望我的ducks不仅具有duck类型,而且还具有quackable类型(这样我就可以拥有只接受quackables的方法——假设还有其他类型是quack类型——请参见lake类)。当我在mallardduck中实现接口时,编译器抱怨这个类没有方法quack,尽管它是在它的超类duck类中定义的。
现在我可以想出两个解决办法:
通过从超类调用方法来覆盖方法庸医:super.quack()<-但这似乎是不必要的(理论上)-子类可以直接访问超类的公共方法,那么为什么接口庸医甚至抱怨。。。?
makeduck实现quackable->这是相当不合逻辑的,因为有些duck不嘎嘎(它们的嘎嘎行为是用siletnquack类实现的)。
然而,在这两种解决方案中,鸭子:
有古怪的行为,并且
是一个摇摇晃晃的人
这不是根本错误吗?我错过了什么?
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();
}
3条答案
按热度按时间wyyhbhjk1#
[就你的问题而言,我更倾向于使用“代表”一词,而不是“行为”,因为我个人认为它更能传达这一概念。]
你的界面
Quackable
意思是“能嘎嘎叫的东西”。甚至是原作
Duck
抽象类有那个方法,所以它已经遵循那个接口,但您“忘记”了声明那个事实。在一个始终如一的世界里,你应该Duck
实施Quackable
从一开始。关于has和is:
全部
Ducks
吃点吧quack()
方法,所以它们是有效的Quackable
(意思是“能嘎嘎叫的东西”)。不管他们如何决定他们的quack()实现,使用继承的委托方法,通过提供不同的delegete/行为修改继承的版本,或者重写方法。事实上他们有
quack()
能力将他们定义为Quackable
.你的鸭子子类也有一个
Quackable
把它当作一个代表,把真正的夸夸其谈推迟到其他一些“行为”的例子(比如政客们自己不发表意见,而是有一个发言人)。所以,上课没什么不对的
Quackable
还有Quackable
同时。在现实世界中,我们都是活生生的动物,我们中的许多人把活生生的动物当作宠物。关于行为对象的一点意见:
尽管这种模式很有用,但要注意,您失去了使
quack()
行为取决于鸭子的状态(例如,在水上或空气中的声音不同)。zu0ti5jz2#
这是因为
Duck
类不实现quack
方法从Quackable
接口。虽然它有一个quack
具有相同签名的方法,它与接口中声明的方法不同。我不明白,为什么解决方案2(使
Duck
类实现Quackable
接口)将是不合逻辑的-它确实公开了用于嘎嘎叫的公共方法,因此它的所有后代都将quack
无论如何(但是不同的quack
是在Quackable
接口)。在我看来(仅此而已)Duck
类应该实现Quackable
.如果(对你来说)不是全部
Ducks
quack
那么,合理的做法是Duck
不能被当作Quackable
行为,因此无法将其添加到Quackable
物体。在这种情况下(在我看来),您可以创建另一个抽象类来扩展Duck
实施Quackable
接口(如QuackingDuck
)在这种情况下(我认为)你应该quack
方法来自Duck
类-不是全部Ducks
quack
.我希望它能回答你的问题。综上所述:
这个
quack
方法来自Duck
不是执行quack
方法来自Quackable
接口(例如javascript)在当前的实施中
Ducks
quack
,只有他们的quacking
行为(实现)是不同的(在SilentDuck
-它还在quacks
)wn9m85ua3#
在超类和接口中都有相同的方法。这个
quack()
mallardduck类中的方法一次做两件事:覆盖
quack()
在超类鸭子里实施
quack()
在quackable界面中。解决方案2帮助您避免这种情况。