好的,所以我正在尝试找出最佳的结构。我想知道在这些情况下,最好的做法是整体上最有效的方法。
比方说,我正在创造一个小世界。这个世界由不同类型的鸟类组成,因此我创建了一个Bird类来充当所有鸟类的父代。
public abstract class Bird {
//stuff all birds have in common
}
现在,我想创建不同类型的鸟类。让我们创建一个Penguin和Goose类,并让它们扩展Bird。
public class Penguin extends Bird{
//penguin stuff
}
public class Goose extends Bird{
//goose stuff
}
到目前为止,一切都很好,但现在是扳手。让我们赋予鸟类飞行的能力。 惊奇,并不是所有的鸟类都能飞翔-例如企鹅!因此,让我们来探讨一下我们的选择。
在Bird类内部设置fly方法是不可行的(并非所有鸟都可以飞行)。另一种令人讨厌的方式是拥有多个父类,例如BirdsThatFly,因为这将变得一团糟,尤其是当其他 birdly 属性添加到混合中时。
在理论上听起来像是正确的主意的一个可行选择是使用接口。例如,我可以有一个Fly界面。
public interface Fly {
public void fly();
}
这将允许我仅在可以飞行的Bird子类上实现Fly。例子..
public class Goose extends Bird implements Fly {
@Override
public void fly() {
//fly!
}
}
这看起来很干净,并强制将fly方法应用到鹅上,并且在添加其他属性时似乎可以很好地工作。
看来是错误的事情是,我仍然必须为每种鸟类创建自定义蝇,并且可能会有大量鸟类!默认空缺会在这里帮助我吗?我认为随着这些属性的增长,它们可能会受到相当大的限制。
也许可以告诉我其他方式以及如何重新考虑此接口结构。
这涉及创建属性对象并将其添加到单个鸟类中。如果我对接口正确,则此选项可能是有效的方法。
属性类看起来像这样
public abstract class Attribute {
public abstract void execute();
}
一个属性可能看起来像这样
public class Fly extends Attribute{
@Override
public void execute() {
//fly!
}
}
现在可以通过在Bird中具有一个属性列表并将其填充到bird类型类中,将该fly属性添加到鸟中。
public abstract class Bird {
private List<Attribute> attributes = new ArrayList<Attribute>();
protected void addAttribute(Attribute attribute){
attributes.add(attribute);
}
public List<Attribute> getAttributes(){
return attributes;
}
}
并将其添加到鹅...
public class Goose extends Bird{
public Goose(){
super.addAttribute(new Fly());
}
}
对我来说,这种方法似乎非常可定制,但似乎不可行,可能无法立即弄清每个班级的能力。为了能够执行特定的属性,还需要进行大量工作才能正确地进行大规模设置。
是否有一种方法可以被认为是更好的实践,或者这是一个合理的方法还是一个好的开始?
答案 0 :(得分:3)
如果所有飞鸟共享相同的飞行方法,则可以使用多个继承级别。
创建一个主要的Bird
对象,该对象处理所有鸟类可以执行的操作。然后创建两个扩展Bird
的子类,例如FlyingBird
和GroundedBird
。这是分离每种Bird
的能力的更合适的方法。
abstract class Bird {
void eat() {
// Because all birds get hungry
}
}
abstract class FlyingBird extends Bird {
void fly() {
// Do the flight!
}
}
abstract class GroundedBird extends Bird {
void waddle() {
// They gotta get around somehow.
}
}
class Penguin extends GroundedBird;
class Goose extends FlyingBird;
编辑
还有两个其他选项可用于处理更多属性。 OP还询问(在下面的评论中)如果鸟可以飞并且游泳的话该怎么办?
在继承链中的某个时刻,您将需要以任何一种方式实现行为。如果您要定义Bird
的多个属性,则可以使用接口来代替:
class Goose extends Bird implements Flyable {
@Override
public void fly() {
// Need to override the fly() method for all flying birds.
}
}
现在,假设您希望所有飞鸟都具有相同的飞行动作。尽管不一定是主意,但您可以创建一个名为BirdAction
的静态类来容纳鸟可能具备的所有“动词”。
您仍然需要为每个fly()
覆盖Bird
方法,但要让它们全部在BirdAction
中调用相同的静态方法:
class BirdAction {
static void fly(Bird bird) {
// Check if this Bird implements the Flyable interface
if (bird instanceof Flyable) {
// All birds fly like this
} else {
// This bird tried to fly and failed
}
}
}
我不会说这是一个理想的解决方案,但是取决于您的实际应用程序,它可能会起作用。 当然,Penguin
缺省不具有fly()
方法,但是如果您仍然从BirdAction.fly()
类调用Penguin
,则可以进行检查。
答案 1 :(得分:1)
这只是有关面向对象设计的一些基本思想。没有更具体的信息,就很难做出明确的决定,那就是设计类或接口。
继承,行为和属性主要影响设计。设计方式还取决于大小(想到的数量,类型和种类)。可以看看Java语言本身的继承设计,例如集合-Collection
接口和Map
接口及其实现。
以下是一些即时想法:
public interface Bird {
public void eat();
public void layEggs();
}
// Provides implementations for _some_ abstract methods and _no_ new methods.
// Also, some implementations can just be empty methods.
public abstract class AbstractBird implements Bird {
public void eat() {
// generic eating implementation
}
public abstract void layEggs(); // no implementation at all
}
// Specific to ground-oriented with Bird behaviour
public interface GroundBird extends Bird {
public void walk();
}
// Specific to air-oriented with Bird behavior
public interface FlyBird extends Bird {
public void fly();
}
// Ground-oriented with _some_ bird implementation
public class Penguin extends AbstractBird implements GroundBird {
public void walk() {
}
public void layEggs() {
// lays eggs on ground
}
// Can override eat if necessary
}
// Air-oriented with _all_ bird implementation
public class Eagle implements FlyBird {
public void fly() {
}
public void layEggs() {
// lays eggs on trees
}
public void eat() {
// can eat while flying
}
}
此设计将允许:
pluck()
界面中提供更多类似Bird
的方法,并且仅在AbstractBird
中实现。AbstractBird
,
使用更具体的实现直接实现Bird
接口
eat
和layEggs
中的第一个。这也允许新的鸟类扩展
新类或抽象类。WaterBirds
*。*
public interface WaterBird {
public void swim();
}
public class Duck implements WaterBird, GroundBird {
public void swim() {
}
public void walk() {
}
public void eat() {
}
public void layEggs() {
// lays eggs on ground
}
}
并且可以创建新的界面,例如Diveable
代表可以潜入水中捕捞鱼的鸟类,Glideable
代表可以飞翔和滑翔的鸟类。可以看到Glideable
是飞鸟的一种特殊行为。还要注意,Glidable
也是HangGlider的行为,鸟类和飞机都共享。
public interface Glideable {
public void glide();
}
public class Eagle extends AbstractBird implements FlyBird, Glideable {
public void fly() {
}
public void glide() {
// eagle specific
}
public void layEggs() {
// lays eggs on trees
}
// Can override eat if necessary
}
注意:从Java 8开始,可以考虑在接口中使用 static 和 default 方法。