She*_*eli 165 java oop multiple-inheritance diamond-problem multiple-interface-implem
为了完全理解如何解决Java的多重继承问题,我有一个经典的问题需要澄清.
可以说我有类Animal
此有子类Bird
和Horse
我需要做一个类Pegasus
,从扩展Bird
和Horse
自Pegasus
既是一只鸟和一匹马.
我认为这是经典的钻石问题.从我能理解经典的方式来解决,这是使Animal
,Bird
和Horse
类接口,并实现Pegasus
从他们.
我想知道是否有另一种方法来解决我仍然可以为鸟类和马创造物体的问题.如果有一种方法可以创造动物,那将是伟大的但不是必要的.
Mor*_*sen 115
您可以为动物类(生物学意义上的类)创建接口,例如public interface Equidae
马匹和public interface Avialae
鸟类(我不是生物学家,所以这些术语可能是错误的).
然后你仍然可以创建一个
public class Bird implements Avialae {
}
Run Code Online (Sandbox Code Playgroud)
和
public class Horse implements Equidae {}
Run Code Online (Sandbox Code Playgroud)
并且
public class Pegasus implements Avialae, Equidae {}
Run Code Online (Sandbox Code Playgroud)
为了减少重复代码,您可以创建一个抽象类,其中包含您要实现的动物的大多数常用代码.
public abstract class AbstractHorse implements Equidae {}
public class Horse extends AbstractHorse {}
public class Pegasus extends AbstractHorse implements Avialae {}
Run Code Online (Sandbox Code Playgroud)
我想补充一点细节.正如布莱恩所言,这是OP已经知道的事情.
但是,我想强调一下,我建议绕过接口的"多继承"问题,我不建议使用代表已经具体类型的接口(如Bird),但更多的是行为(其他指的是鸭子打字,这也很好,但我的意思是:鸟类的生物类,Avialae).我也不建议使用以大写"I"开头的接口名称,例如IBird
,它只是告诉您为什么需要接口.这就是问题的不同之处:使用接口构造继承层次结构,在有用时使用抽象类,在需要时实现具体类,并在适当时使用委托.
Tim*_*m B 87
将对象组合在一起有两种基本方法:
这种方式的工作方式是你有一个Animal对象.然后在该对象中添加进一步的对象,这些对象提供您需要的属性和行为.
例如:
现在IFlier
看起来像这样:
interface IFlier {
Flier getFlier();
}
Run Code Online (Sandbox Code Playgroud)
所以Bird
看起来像这样:
class Bird extends Animal implements IFlier {
Flier flier = new Flier();
public Flier getFlier() { return flier; }
}
Run Code Online (Sandbox Code Playgroud)
现在你拥有继承的所有优点.您可以重复使用代码.您可以拥有一组IFliers,并可以使用多态性等所有其他优点.
但是,您也拥有Composition的所有灵活性.您可以根据需要为每种类型应用尽可能多的不同接口和复合支持类Animal
- 尽可能多地控制每个位的设置.
策略模式替代组合方法
根据您正在做什么以及如何做的另一种方法是让Animal
基类包含一个内部集合来保存不同行为的列表.在这种情况下,您最终会使用更接近战略模式的东西.这确实在简化代码方面具有优势(例如Horse
,不需要知道任何关于Quadruped
或的东西Herbivore
),但如果你不进行接口方法,则会失去多态性等许多优点.
Pav*_*cek 41
我有一个愚蠢的想法:
public class Pegasus {
private Horse horseFeatures;
private Bird birdFeatures;
public Pegasus(Horse horse, Bird bird) {
this.horseFeatures = horse;
this.birdFeatures = bird;
}
public void jump() {
horseFeatures.jump();
}
public void fly() {
birdFeatures.fly();
}
}
Run Code Online (Sandbox Code Playgroud)
snr*_*rlx 25
我可以建议鸭子打字的概念吗?
很可能你倾向于让Pegasus延伸一个Bird and a Horse界面,但鸭子打字实际上暗示你应该宁愿继承行为.正如评论中已经说明的那样,飞马座不是一只鸟,但它可以飞翔.所以你的Pegasus应该继承一个接口Flyable
,让我们说一个接口Gallopable
.
战略模式中使用了这种概念.在给定的例子其实显示了一只鸭子如何继承FlyBehaviour
和QuackBehaviour
,仍然可以有鸭,例如RubberDuck
,它不能飞.他们本可以使Duck
延伸成为一级,Bird
但是他们会放弃一些灵活性,因为每个人Duck
都可以飞,甚至是穷人RubberDuck
.
Smu*_*tje 18
从技术上讲,你一次只能扩展一个类并实现多个接口,但是当涉及到软件工程时,我宁愿建议一个特定于问题的解决方案,而不是一般的问题.顺便说一下,这是一个很好的OO实践,不扩展具体类/只扩展抽象类来防止不必要的继承行为 - 没有"动物"之类的东西,也没有使用动物对象而只使用混凝土动物.
Ian*_*ose 12
将马放在有半门的马厩里是安全的,因为马不能越过半门.因此,我设置了马匹服务,接受任何类型的马类,并把它放在一个半门的马厩里.
那种像马一样的动物甚至可以飞马吗?
我过去常常考虑多重继承,但是现在我已经编程了超过15年,我不再关心实现多重继承了.
通常情况下,当我试图应对一个指向多重继承的设计时,我后来发布了我错过了解问题域.
要么
Java没有多重继承问题,因为它没有多重继承.这是设计,以解决真正的多重继承问题(钻石问题).
有不同的策略可以缓解这个问题.最容易实现的是Pavel建议的Composite对象(实质上是C++如何处理它).我不知道通过C3线性化(或类似)的多重继承是否适用于Java的未来,但我对此表示怀疑.
如果你的问题是学术性的,那么正确的解决方案是鸟和马更具体,假设飞马只是一只鸟和马的组合是错误的.说Pegasus具有与鸟类和马匹相同的某些内在特性(即它们可能具有共同的祖先)会更为正确.Moritz的答案指出,这可以充分模仿.
我认为这在很大程度上取决于您的需求,以及您的动物类如何在您的代码中使用.
如果您希望能够在Pegasus课程中使用您的马和鸟实施的方法和功能,那么您可以将Pegasus实施为鸟和马的组合:
public class Animals {
public interface Animal{
public int getNumberOfLegs();
public boolean canFly();
public boolean canBeRidden();
}
public interface Bird extends Animal{
public void doSomeBirdThing();
}
public interface Horse extends Animal{
public void doSomeHorseThing();
}
public interface Pegasus extends Bird,Horse{
}
public abstract class AnimalImpl implements Animal{
private final int numberOfLegs;
public AnimalImpl(int numberOfLegs) {
super();
this.numberOfLegs = numberOfLegs;
}
@Override
public int getNumberOfLegs() {
return numberOfLegs;
}
}
public class BirdImpl extends AnimalImpl implements Bird{
public BirdImpl() {
super(2);
}
@Override
public boolean canFly() {
return true;
}
@Override
public boolean canBeRidden() {
return false;
}
@Override
public void doSomeBirdThing() {
System.out.println("doing some bird thing...");
}
}
public class HorseImpl extends AnimalImpl implements Horse{
public HorseImpl() {
super(4);
}
@Override
public boolean canFly() {
return false;
}
@Override
public boolean canBeRidden() {
return true;
}
@Override
public void doSomeHorseThing() {
System.out.println("doing some horse thing...");
}
}
public class PegasusImpl implements Pegasus{
private final Horse horse = new HorseImpl();
private final Bird bird = new BirdImpl();
@Override
public void doSomeBirdThing() {
bird.doSomeBirdThing();
}
@Override
public int getNumberOfLegs() {
return horse.getNumberOfLegs();
}
@Override
public void doSomeHorseThing() {
horse.doSomeHorseThing();
}
@Override
public boolean canFly() {
return true;
}
@Override
public boolean canBeRidden() {
return true;
}
}
}
Run Code Online (Sandbox Code Playgroud)
另一种可能性是使用实体 - 组件 - 系统方法而不是继承来定义您的动物.当然,这意味着您不会拥有动物的单独Java类,而是仅由它们的组件定义.
实体 - 组件 - 系统方法的一些伪代码可能如下所示:
public void createHorse(Entity entity){
entity.setComponent(NUMER_OF_LEGS, 4);
entity.setComponent(CAN_FLY, false);
entity.setComponent(CAN_BE_RIDDEN, true);
entity.setComponent(SOME_HORSE_FUNCTIONALITY, new HorseFunction());
}
public void createBird(Entity entity){
entity.setComponent(NUMER_OF_LEGS, 2);
entity.setComponent(CAN_FLY, true);
entity.setComponent(CAN_BE_RIDDEN, false);
entity.setComponent(SOME_BIRD_FUNCTIONALITY, new BirdFunction());
}
public void createPegasus(Entity entity){
createHorse(entity);
createBird(entity);
entity.setComponent(CAN_BE_RIDDEN, true);
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
135326 次 |
最近记录: |