当前位置: 首页 > 面试题库 >

我的Java Game项目中是否过度使用了静态功能?

宇文曦
2023-03-14
问题内容

我目前正在用Java开发一个小平台,并为此编写了自己的游戏引擎,名为Bonsai。现在我问自己一个问题:“我是否过度使用了静态方法?”。

一方面,这非常方便,因为我不必在每个类(例如地图或玩家)中都引用游戏实例。另一方面,我已经不得不去除applet的支持了,因为那里所有静态的东西都非常小。

所以我的问题是,由于您可能比我更有经验的Java程序员,我应该摆脱所有的静态知识吗?如果是的话,什么是达到以下目的的有效方法:

public void draw(Graphics2D) {
  if (this.game.time() > this.timer) {
    this.game.image.draw(this.tiles[this.game.animation.get("tileAnim")], x, y, null)
  }
}

代替:

public void draw(Graphics2D) {
  if (Game.time() > this.timer) {
    Image.draw(this.tiles[Animation.get("tileAnim")], x, y, null)
  }
}

甚至在地图编辑器中更糟:

   public void control() {
     if(this.map.game.input.keyPressed(...)) {
       this.map.game.sound.play(...);
     }
   }

编辑
根据答案,我决定创建一个GameObject类,该类为每个组件提供包装方法。地图,玩家等,然后从中子类化,这样,我所有this.game调用都隐藏在场景的后面,并且在正面看起来仍然不错:

public class GameObject {
    private Game game;

    public GameObject(Game g) {
        game = g;
    }

    public Game Game() {
        return game;
    }

    public GameAnimation Animation() {
        return game.animation;
    }

    public GameInput Font() {
        return game.input;
    }

    // ...

    public long Time() {
        return game.time();
    }
}

现在,代码如下所示:

public class Player() {
    public Player(Game g, int xpos, int ypos) {
      super(g);
      // do other stuff
    }

    public void jump() {
      // jump code
      Sound().play("jump");
    }
}

还是Java更糟糕?

EDIT2
好吧,我已经在使用方法调用时遇到了问题,编译器给了我错误,因为它无法在原始版本中找到我的子类Game的方法,我想我要在这里使用纯字段。

EDIT3
好吧,我的 _ GameObject_ 类现在看起来像这样,一切都再次正常运行,我可以重新实现applet支持:)

public class GameObject {
    protected Game game;
    protected GameAnimation animation;
    protected GameFont font;
    protected GameInput input;
    protected GameImage image;
    protected GameSound sound;

    public GameObject(Game g) {
        game = g;
        animation = game.animation;
        font = game.font;
        input = game.input;
        image = game.image;
        sound = game.sound;
    }
    }

问题答案:

首先。

您不必仅仅因为这将使它在“纸上”更好而摆脱所有静态代码。

您确实必须了解实例代码(非静态)和类代码(静态)之间的区别

*当方法/属性不需要类的实例来工作时,将使用 *静态 代码(类方法/属性)。一个很好的例子是图像绘制方法:Image.draw()

实例 方法/属性对于保持给定对象的 状态 非常有用,该对象必须与其他对象中的数据保持分开。

例如,如果您Player在游戏中上课,并且有两个实例,player1并且player2每个实例都有自己的得分是有意义的:

 public class Player {
     private int score;
     private String name;
     etc.....
 }

 Player one = new Player("Player 1");
 display( one.score );

 Player two = new Player("Player 2");
 display( two.score );

不必创建文物来保持每个玩家的得分(例如将它们放入每个索引均为属性的数组中并使该数组静态等)。

其次

您可以object1.atr2.other.next.etc通过为对象分配适当的属性并以正确的方式执行封装来减少提到的构造。

如果一个对象b需要访问另一个对象的第N个元素,a则该属性可能属于该对象b而不是该对象,a或者该对象a应该提供一种避免暴露其内部的方法。

它甚至使代码更易于阅读:

即。

public void draw(Graphics2D) {
  if( this.game.needsDrawing() ) {
       this.game.draw();
  }
}

代替:

public void draw(Graphics2D) {
    if (this.game.time() > this.timer) {
        this.game.image.draw(this.tiles[this.game.animation.get("tileAnim")], x, y, null)
    }
}

再次,这取决于情况,在某些情况下您可能不需要实例(同样,例如Image的draw()实用程序方法)

最后。

实例方法允许您使用多态,而类方法则不允许(至少在Java和其他静态类型的语言中)。

因此,如果您的代码是实例代码,则可能会受益于使用运行时委托和多态性。以状态模式为例,如果所有代码都是静态的,则不能使用它,但是可以使用实例代码:

class Game {
     GameState state = GameState.getInitialState( this );

     void run() {
         while( state.alive ) {
              do X Y Z
              state.updateState();
          }
     }
  }


class GameState {
    Game context;
    static GameState getInitialState( Game g ) {
        return new StartGameState(g);
    }
    void updateState();
}

class StartGameState {
     void updateState() {
         if( this.context.someCondition() ) {
             this.context.state = new MidGameState();
         }
     }
 }


class MidGameState {
     void updateState() {
         if( this.context.someOtherCondition() ) {
             this.context.state = new EndGameState();
         }
     }
 }

class EndGameState {
     void updateState() {
        Game over... 
     }
 }

再一次,仅在面向对象方面有意义时,例如对象是否具有需要数据的属性?如果不是,最好将那部分代码保持静态。

所有这些概念(封装,多态性,抽象,继承等)都是OO技术的本性,并已包含在OOA /
D中,
尽管它们看起来像语法糖(在大多数情况下是),您的经验会告诉您何时应该有一些作为
代码和何时作为 实例 代码的东西。



 类似资料:
  • 我工作的地方使用Maven,我们有很多内部库。我们尝试以向后兼容的方式进行更改,但有时我们的一个库需要另一个库的较新版本。如果最终产品没有加入较新的库版本,这可能会导致问题。 由于我们有很多库,如果最终产品使用了库A、B和C,而A和B都使用了不同版本的C,那么并不总是使用最新版本的C。从介绍到依赖机制: 依赖项中介--这确定当遇到工件的多个版本时,将使用依赖项的哪个版本。目前,Maven2.0只支

  • 这两个函数是否重载

  • 问题内容: 我已经读过1000多个位置,这些位置不继承静态变量。但是,这段代码如何正常工作? Parent.java Child.java 此代码显示“父母”。 还阅读了一些隐藏数据的概念。 Parent.java Child.java 现在输出为“ Child”。 那么这是否意味着 静态变量被继承,但是它们遵循数据隐藏的概念 ? 问题答案: 请查看oracle的文档:http : //docs.

  • 问题内容: 我唯一了解的是 如果使用其 方法,它将始终返回而不是对象。它有什么用? 通过使用,您可以确保无法从 方法中恢复该对象。 但是这个概念/类的用途是什么? 您是否曾在您的任何项目中使用过此功能,或者在任何示例中应使用此功能? 问题答案: 我在简单,非常专业的内存分析器中使用s来监视对象的创建和销毁。我需要他们追踪破坏。但是这种方法已经过时了。(它于2004年针对J2SE1.4编写。)专业的

  • 问题内容: Quickcheck及其变体(甚至Java中也没有)似乎很有趣。但是,除了学术兴趣之外,它在实际的应用程序测试中是否真的有用(例如GUI应用程序或Client / Server甚至是StackOverflow本身)?您使用类似的测试生成器的任何经验都将受到赞赏。 问题答案: 好吧。其实没有,但是我是在最初开发QuickCheck的那个人的带领下学习的,他是一个非常有趣的人。 早在200

  • 问题内容: 我正在阅读Khalid Mughal 撰写的Java™SCJP认证程序员指南。 在“继承”一章中,它说明了 成员的继承与声明的可访问性紧密相关。如果超类成员可以通过子类中的简单名称来访问(不使用任何其他语法,如super),则该成员被视为继承的 它还提到静态方法不是继承的。但是下面的代码完全可以: 我如何直接在课堂上使用?甚至更多,也可以。 这本书的解释仅适用于实例方法吗? 问题答案: