了解何时使用继承,以及

时间:2017-08-19 11:58:45

标签: java inheritance

我目前还不确定继承最适合我的Java程序,或者最好是否使用接口实现。我正在讨论的上下文的一个例子如下。

想象一下,我正在制作游戏,我的游戏中有敌人。这些敌人都有各种各样的变量和行为,但在某种程度上都是独一无二的。例如,Enemy1,

class Enemy1 {

    float x, y, width, height;

    public Component(float x, float y, float width, float height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
    public void AI() {
        //some code
    }
}

和Enemy2,

class Enemy2 {

    float x, y, width, height;

    public Component(float x, float y, float width, float height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
    public void AI() {
        //some different code
    }
}

所以对于这两个不同的敌人,我理解(或者至少相信)我可以将Enemy2改为类似

class Enemy2 extends Enemy1 {
    @Override
    public void AI() {
        //some different code
    }
}

但是,现在如果我有五种不同类型的AI代码,每个敌人可以拥有,然后不是为每个敌人在类中定义AI行为的代码,我想要另一个包含所有敌人的类AI,允许我扩展/实现AI类/接口并选择我想要的那个。

我不确定最好的办法是做什么的。简而言之,我希望有不同的敌人共享属性,每个属性中都有类似但不同的功能(例如AI代码),但总体来说仍然是非常独特的。仅使用课程来实现这一目标是否最有效?接口?我该怎么做呢?我是否会有一个班级从班级中汲取课程?或者只是一个类扩展一个类并同时实现一个接口?我不太清楚最好的继承结构是什么用。

对不起,如果我有任何根本的误解或错误。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

  

类Enemy2扩展了Enemy1

这在语义上是否有意义? Enemy2 Enemy1吗?对游戏一无所知,让我们说Enemy1是一只恐狼,而Enemy2是一只熊。熊也不是恐狼,所以这种结构毫无意义。但是,如果Enemy2是一个Dire Wolf Pack Leader,那么这个有意义,因为它也是一个恐怖狼。

  

我想要另一个包含所有AI的类

这对我来说听起来很奇怪。一个对象包含其他对象的所有逻辑,并从中提取逻辑?这听起来非常接近“上帝对象”的反模式。您应该将逻辑保留在拥有它的对象上。

根据描述,听起来你想要一个abstract class。一个基础Enemy类,它本身不能被实例化,但它拥有所有敌人的共性。类似的东西:

abstract class Enemy {

    float x, y, width, height;

    public Enemy(float x, float y, float width, float height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

    abstract public void AI();
}

然后任何敌人都会继承:

class DireWolf extends Enemy {
    public DireWolf(float x, float y, float width, float height) {
        super(x, y, width, height);
    }
    public void AI () {
        //...
    }
}

实际上,任何扩展Enemy的类都将由编译器 来实现AI()。因此,通用功能通用接口保存在抽象基类中,从中继承的每个类都将为该接口提供实现。

修改

此方法需要constructor for every child class。这可能对您有利,例如,如果每个DireWolf的大小相同,构造函数可能如下所示:

    public DireWolf(float x, float y) {
        super(x, y, 64, 64);
    }

然后你可以按如下方式初始化你的狼:

Enemy wolf = new DireWolf(0, 0);

答案 1 :(得分:1)

您可以使用过程函数创建一个抽象的AI类:

abstract class AI
{
   public abstract void process(Enemy en);
}

然后你可以扩展它。

class AISipleMovement extends AI
{
   @Override
   public void process(Enemy en)
   {
        en.moveRandomly(); //Insert actual code here
   }
}

或只是:

class AIStayFrozen extends AI
{
   @Override
   public void process(Enemy en)
   {

   }
}

在敌人类中:

class Enemy1 {
    float x, y, width, height;
    AI ai;

    public Enemy1(float x, float y, float width, float height, AI ai) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.setAI(ai)
    }

    public void setAI(AI aiIn)
    {
        this.ai = aiIn;
    }

    public void AI() {
        ai.process(this);
    }
}

当然,这是一个最小的例子,你应该覆盖ai是否为空以防止NullPointerException和类似的东西。