【问题标题】:OOP: Object Inheritance and Composition Relationships in Simple Game Design [closed]OOP:简单游戏设计中的对象继承和组合关系[关闭]
【发布时间】:2013-02-21 22:24:58
【问题描述】:

我目前学习 Java 有几个原因,其中一个主要原因是它是一种非常面向 OOP 的语言,而用 Java 编写代码确实有助于我理解 OOP 编程背后的核心概念。

但是,我在定义我的类之间的关系时遇到了困难。我了解继承和组合之间的区别,但我很难看清全局,以及我的所有类应该如何作为一个整体协同工作。

我将如何使用 OOP 编写简单的井字游戏的示例;

  1. 创建Game 类 - 创建gameBoard 类的实例, 决定谁先开始,跟踪比赛的输赢,开始 并结束游戏。

  2. 创建一个gameBoard 类 - 更新井字游戏板, 确定下一位玩家的回合,如果移动是合法的,并且 确定何时有赢家

  3. 创建一个抽象的Player 类 - 保存玩家的图块(X 或 O),并且 包含一个将gameBoard 实例作为参数的方法,并且 将玩家的移动传递给实例引用

  4. 创建一个扩展 Player 类的 Human 类。包含 处理来自键盘的玩家输入的方法

  5. 创建一个扩展 Player 类的 Computer 类。有个 将gameBoard 实例作为参数并分析的方法 制胜棋步、阻挡棋步或任何其他棋子的棋盘 移动,然后移动

这是我将采取的方法。但是,我在将所有课程联系在一起时遇到了一些麻烦。在某些情况下,关于某些方法和字段应该属于何处的界限似乎有些模糊。

编辑:修改后的问题:

在为我的类确定清晰、已定义的角色时,什么是一种好的方法,而不是太忙于尝试定义和封装我的程序的各个方面?我的很多对象可以从其他类调用来执行每个类具有的特定功能,即Player更新gameBoardgameBoard更新Game,但我不知道这是否是一个好习惯,或者传递过多的对象引用会使代码变得僵硬且难以维护。

【问题讨论】:

  • 您的问题过于宽泛,无法合理回答。您能否进一步简化并以您想回答的具体问题结束(我可以在您的文本中看到很多问题,每个问题都不容易回答)?
  • 我会尝试将我的问题重新表述为一个具体问题。
  • 来自堆栈溢出常见问题解答:“你的问题应该有合理的范围。如果你能想象一本书可以回答你的问题,那你就问得太多了。”这不是堆栈溢出的问题。
  • 我的问题很具体,但我发现很难简洁地表达出来。我的问题是关于创建明确定义的类和可读的代码。
  • 我同意 vikingsteve 的回答,他说对 Gameboard 重视没有多大意义是对的。 Gameboard 只是一个被动实体,将由玩家更新并由 Game(或 GameController)评估。

标签: java oop inheritance composition


【解决方案1】:

Martyn,尝试将问题中的每个关系归类为“is-a”或“has-a”。这将更容易解决类关系。

例如,

Game has-a Gameboard
Human is-a Player
Computer is-a Player

然后

Game has-a Player1
Game has-a Player2

等等

看看你是怎么做的,你会回答很多你自己的问题。祝你好运!

编辑:您写道:Player 更新 gameBoardgameBoard 更新 Game

你能不能这样做,让“游戏”在游戏控制中更加重要?

Game asks player to select next move from GameBoard
Player looks on Gameboard to see possible legal moves
Player selects a legal move and returns it to Game
Game plays the move on the GameBoard
Game checks the Gameboard to see if any player has won
if not, Game ends the turn and goes to the next player
...

【讨论】:

  • 我理解 has-a 和 is-a 的关系,但通过进一步分解对象来添加不必要的抽象级别总是很诱人。我仍在尝试在可重用性和抽象性之间找到适当的平衡。
  • 你的课堂创意非常好,不过我可以建议让 Game 对游戏的控制更加重要(请参阅我的编辑)。
  • 我可以看到让游戏更集中于整体控制的好处。就对象关系而言,让 Player 处理在 GameBoard 上下棋似乎更自然,但就可重用性而言,让 Game 充当正在玩的任何游戏的整体控制器似乎是合乎逻辑的,并且会增加额外的扩展 Game 类的游戏更易于自上而下管理。
  • 没错。你现在走在正确的轨道上,马丁!一个遥远的类设计类比可能是 MVC(用于 GUI 设计),它也有一个“控制器”。
  • 有趣的是,当我阅读您的建议时,我想到的正是“控制器”这个词,从设计的角度来看,它很有意义。我想我现在有足够的信息来设计我的程序。我认为我的问题得到了回答。感谢您的帮助。
【解决方案2】:

一个游戏有两个玩家和一个棋盘。在棋盘说游戏结束之前,它应该轮流询问每个玩家以发现他们想要的动作是什么。然后它应该将该动作传递给董事会。如果董事会接受它,因为它是有效的,那么它就是下一个玩家轮到的。如果棋盘因为无效而拒绝了这步棋,那么它会要求同一个玩家再次走棋。

记住这一点,一些伪代码可能采用以下形式;

class Game {
    Player p1, p2, current;
    Board board;

    public Game() {
        Board = new TicTacToeBoard();
        p1 = new Human('X');
        p2 = new Compooterwooter('O');

        current = p1;
    }
}

abstract class Player {
   char label;
   Move getMove(Board);
}

abstract class Board {
   boolean makeMove(Move);
   Position getPosition();
   boolean gameIsUp(); /* has the game finished? */
}

class Move {
   int x, y;
}

class Position {
    boolean isVacant(int x, int y);
    char whoHasPlayed(int x, int y);
}

class Human extends Player {
    Move getMove(Board b) { /* ask user for move */ }
}

class Compooterwooter extends Player {
    Move getMove(Board b) { /* compute move */
}

class TicTacToeBoard extends Board {
   boolean makeMove(int x, int y) { /* check valid move */
}

这不是最有用的答案,但我只是在推测,这似乎至少是一个稍微推测的问题。希望它可以帮助您朝着正确的方向前进。

【讨论】:

  • 在伪代码中看到它确实有助于可视化解决方案。也许我的问题是我试图在我的脑海中想象结构而没有先计划它,并在我开始将击键输入 IDE 之前尝试解决所有问题。也许首先在 UML 中规划我的设计会帮助我更好地可视化类和对象的关系,而不是在定义结构之前试图弄清楚所有事情。
  • 做一点计划可能会有所帮助,是的。但同样重要的是要认识到您只是在学习,并且通过完成某件事而不是花一两天时间在 UML 上胡思乱想,您将学到更多。祝你的项目好运:-)
  • 谢谢。是的,你说得很对。将计划付诸行动,而不是过度计划,我会学到更多。
【解决方案3】:

从下面的代码开始。

然后让它工作,这样你就可以从命令行手动播放双方。

然后将您的代码重构为一些播放器类以及其他任何需要的内容。

enum State {
    x('x'),o('o'),vacant(' ');
    State(char c) {
        this.c=c;
    }
    char c;
}
class Game {
    Game() {
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
                board[i][j]=State.vacant;
    }
    void makeMove(int i,int j,State state) {
        if(board[i][j]!=State.vacant)
            throw new RuntimeException("bad move!");
        board[i][j]=state;
    }
    boolean isGameOver() {
        // ...
        return false;
    }
    public String toString() {
        String s="";
        for(int i=0;i<3;i++) {
            s+='|';
            for(int j=0;j<3;j++)
                s+=""+board[i][j].c+'|';
            s+='\n';
        }
        return s;
    }
    final State[][] board=new State[3][3];
}
public class So15013410 {
    public static void main(String[] args) {
        Game game=new Game();
        System.out.println(game);
        game.makeMove(0,0,State.x);
        System.out.println(game);
        game.makeMove(0,1,State.o);
        System.out.println(game);
    }
}

【讨论】:

  • 谢谢。首先创建一个可用的游戏板是有意义的,然后重构我的代码来处理玩家交互,并定义我的类来处理每个特定的游戏方面。它可能会让我更好地了解我需要哪些类,而不是尝试从偏移量创建它们。
  • 我希望我能接受两个答案,因为您的代码为我提供了一个非常好的起点,我可以使用它,并提供了一个很好的枚举示例。非常感谢。
  • np,他的回答很好。它与类关系有关。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-08
  • 2012-01-30
  • 1970-01-01
  • 2011-04-26
  • 1970-01-01
  • 2021-04-26
  • 1970-01-01
相关资源
最近更新 更多