OOP:简单游戏设计中的对象继承与构成关系

时间:2013-02-21 22:24:58

标签: java oop inheritance composition

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

但是,我很难定义我的课程之间的关系。我理解继承和组合之间的区别,但是我看到整个画面有些困难,以及我的所有课程应该如何整体协作。

我将如何使用OOP编写一个简单的Tic-Tac Toe游戏的例子;

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

  2. 创建一个gameBoard类 - 更新tic-tac-toe板, 如果移动合法,则确定下一个玩家的回合 确定何时有胜利者

  3. 创建一个抽象的Player类 - 保存玩家的牌(X或O),和 包含一个以gameBoard实例作为参数的方法 将玩家所做的动作传递给实例参考

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

  5. 创建一个扩展Computer类的Player类。有个 将gameBoard实例作为参数并进行分析的方法 用于获胜动作,阻挡动作或任何其他动作的游戏板 移动,然后采取行动

  6. 这是我要采取的方法。但是,我在将所有课程联系起来时遇到了一些麻烦。在某些情况下,某些方法和字段应该属于哪一行,这条线似乎有点模糊。

    编辑:修改后的问题:

    在为我的课程确定明确的,定义的角色时,什么是一个很好的方法,而不会过于陷入尝试定义和封装我的程序的每个方面?可以从其他类调用我的很多对象来执行每个类具有的特定功能,即Player更新gameBoardgameBoard更新Game,但我不知道这是不是很好的做法,或者通过传递太多的对象引用来制作严格且难以维护的代码。

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分: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 */
}

这不是最有用的答案,但我只是在猜测,而且它似乎至少是一个略带推测的问题。希望这有助于让你的思想朝着正确的方向发展。

答案 2 :(得分:1)

从下面的代码开始。

然后使其工作,这样您就可以从命令行手动播放双方。

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

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