有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

带有Java接口和抽象类的oop属性继承

好的,所以我想找出最好的结构。我想知道在这些情况下,什么是最佳做法,以及总体上最有效的做法

问题

假设我正在创造一个小世界。这个世界由不同类型的鸟组成,所以我创建了一个鸟类,作为所有鸟的父类

public abstract class Bird {
  //stuff all birds have in common
}

现在我想创造不同类型的鸟。让我们创建一个企鹅和鹅类,并让他们扩展鸟

public class Penguin extends Bird{
    //penguin stuff
}

public class Goose extends Bird{
    //goose stuff
}

到目前为止还不错,但现在是扳手。让我们给鸟儿飞翔的能力<出乎意料的是,并不是所有的鸟都会飞——比如企鹅!让我们来探讨我们的选择

在Bird类中创建一个fly方法是不可能的(不是所有的Bird都会飞)。另一种难闻的方式是有多个父类,比如BirdShatfly,因为这会变得非常混乱,尤其是当其他birdly属性被添加到组合中时

选项1

接口

从理论上讲,一个可行的选择听起来是正确的,那就是使用接口。例如,我可以有一个飞行界面

public interface Fly {
    public void fly();
}

这将允许我实现只在能飞行的Bird子类上飞行。例如

public class Goose extends Bird implements Fly {
    @Override
    public void fly() {
        //fly!
    }
}

这看起来很干净,并强制在goose上使用fly方法,而且在添加其他属性时,它似乎可以很好地工作

似乎不对的是,我仍然需要为每种类型的鸟创建一个定制的苍蝇,而且可能会有很多鸟!默认的空隙能帮我吗?我觉得随着这些属性的增长,它们可能会受到相当大的限制

也许我可以被告知其他情况,以及如何重新思考这个接口结构

选择2

我自己的属性类

这涉及到创建属性对象并将它们添加到各个bird类中。如果我对接口的理解是正确的,那么这个选项可能是一种有效的方法

属性类看起来像这样

public abstract class Attribute {
    public abstract void execute();
}

属性可以是这样的

public class Fly extends Attribute{
    @Override
    public void execute() {
        //fly!
    }
}

这个fly属性现在可以添加到bird中,方法是在bird中有一个属性列表,并将其填充到bird type类中

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());
    }
}

对我来说,这种方法似乎非常可定制,但也似乎不太实际,可能无法立即明确每个类都能做什么。它还需要大量工作才能在更大范围内正确设置,以便能够执行特定属性

有没有一种方法可以被认为是更好的实践,或者这是一种合理的方法还是一个良好的开端


共 (2) 个答案

  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
        }
    }
    

    这种设计将允许:

    • 稍后在Bird接口中提供更多类似pluck()的方法,并且只在AbstractBird中实现
    • 另外,一些类别类可以完全跳过AbstractBird,并且 用更具体的实现直接实现Bird接口 关于{}和{}。这也使得一种新的鸟类得以扩展 新类或抽象类
    • 以后再添加其他种类的鸟,比如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是飞鸟的一种特殊行为。还要注意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,可以考虑使用静态默认方法。p>

  2. # 2 楼答案

    如果所有的飞鸟都有相同的飞行方法,你可以使用多个层次的遗传

    创建一个主Bird对象,处理所有鸟类都能做的动作。然后创建扩展Bird的两个子类,比如FlyingBirdGroundedBird。这是一种更合适的方式来区分每种类型的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的静态类来保存一只鸟可能会使用的所有“动词”

    您仍然需要为每个Bird重写fly()方法,但让它们在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()方法,但如果仍然从Penguin类调用BirdAction.fly(),则会进行检查