2

为了帮助了解 Objective-C,我正在创建一个非常基本的无 Cocoa 连接 4 游戏。

在我的程序中,我有三个模块:

  • “游戏”:包含一个保存棋盘信息的数组。在 main 中创建并负责转弯的对象。Player 和 Computer 对象位于该模块中。
  • “玩家”:拥有一个将玩家的棋子插入首选列的函数(此模块的存在是为了封装,仅此而已)。
  • “计算机”:包含根据当前板设置确定计算机应移动的位置的功能,然后将一块放置在该位置。

理想情况下,我希望 Player 和 Computer 类能够pieceLoc通过某种继承来编辑存在于 Game 中的相同实例,但是我不确定如何执行此操作。

这是我目前正在考虑的一个片段:
// startGame exists within the "Game" module

char *pieceLoc[42]; // This is a *temporary* global var. I'm still learning about
                    // the best way to implement this with class and instance 
                    // methods. This is the array that holds the board info.

-(void) startGame {
 Player   *player   =[[Player alloc] init]; // player's symbol = 'X'
 Computer *computer =[[Computer alloc] init]; // computer's symbol = 'O'

 int i = 0;
 while ([game hasPieceWon: 'X'] == NO && [game hasPieceWon: 'O'] == NO) {
  //function for player move

      if ([game hasPieceWon: 'X'] == NO) {
      //function for computer move
      } 
  }
 if ([game hasPieceWon: 'X'] == YES)
   // Tell the player they've won 
 else
  // Tell the player the computer has won.

}

用于玩家和计算机移动的函数是需要以某种方式获得对数组的访问权限的函数pieceLoc(一旦我了解更多关于类与实例方法的信息,它将作为实例变量存在)。pieceLoc当前以 char * 形式存在,以防我必须通过函数参数传递它。

我觉得这是一个关于我如何考虑 OOP 的相当简单的问题,但是尽管我在下午的大部分时间都在寻找我所寻找的东西,但我还是找不到答案。从我收集到的问题中,我的问题与类组成有关,但我找不到关于 Objective-C 的好的资源。

所以,再次:我正在寻找一种方法,将pieceLoc“父类”游戏中的单个实例传递给两个“子类”,无需使用其他参数pieceLoc即可直接对其进行操作。

如果将数组作为参数传递最终确实是更惯用的做法,我能否获得一个示例,说明在 Objective-C 中如何通过引用传递?

谢谢您的帮助!

4

2 回答 2

4

正如您可能已经发现的那样,Objective-C 并没有真正可以从超类继承的“类变量”。

构造它的一种方法是你不必有全局变量是这样的:

您有一个 Game 对象,其中包含对每个玩家和棋盘的引用。每个播放器都使用对板的引用进行初始化。您的 startGame 方法(在 Game 中)将具有如下代码:

board = [[Board alloc] init];
player = [[Player alloc] initWithBoard: board];
computer = [[ComputerPlayer alloc] initWithBoard: board];

在 Board 类中,您将有一些方法来查询棋盘的状态、移动、确定移动是否合法以及玩家是否获胜(尽管游戏规则相关的逻辑可能会进入游戏)。

在 Player 和 ComputerPlayer 的 initWithBoard 方法中,您只需保留棋盘实例,并使用它来传达每个玩家决定做出的动作。游戏将建立移动顺序,并跟踪任何全局状态。当 Player 和 ComputerPlayer 在游戏结束时被释放时,他们会在他们的 dealloc 方法中释放他们对棋盘的引用。

于 2009-12-29T03:49:36.993 回答
1

由于 Objective-C 本身没有类变量(它们只是使用静态变量模拟),如果您在同一源文件/编译单元中定义方法,子类只能直接访问静态全局变量。这打破了其他最佳实践(每个编译单元一个类定义)。访问类字段的常用方法是使用访问器。

在这种情况下,请注意不要将类耦合得太紧。将棋盘(作为对象,而不是数组)传递给PlayerPerson可能是一个更好的名称,因为计算机也是玩家)和Computer,无论是作为方法参数还是属性,都比引用全局或另一个类的静态成员更灵活。玩家对象决定放置位置,然后告诉棋盘放置棋子的位置。或者,游戏将棋盘的只读版本传递给玩家;玩家的放置方法返回放置棋子的位置。一方面,解耦和使用板对象可以防止作弊。想象一下,有人注入了他们自己的 Player 类,让他们轮流放置多个棋子。另一方面,它的间接性使得添加网络支持变得更容易(对象之间的消息在对本地对象透明的过程中变成网络消息)。

还要考虑创建球员的位置。让其他东西创建玩家并将它们传递给startGame方法可能更有意义。例如,如果玩家在锦标赛中竞争,并且玩家对象因此需要存在比单个游戏更长的时间,这将是有意义的。

类组合是指一个对象具有另一个作为成员。例如,C 不支持继承,但允许嵌套结构。另一种说法是类组合是关于“has-a”关系,而继承是关于“is-a”关系。例如,玩家类可以有一个指向棋盘的指针,每个棋盘都用来放置棋子。

Objective-C 也没有传递引用。相反,它使用指针。

此外,请确保您的游戏处理平局。您可能希望简化游戏循环来完成此操作。在伪代码中,

// nextPlayer returns 'nil' if game is over (win or tie)
while currPlayer := [game nextPlayer]:
    // player will tell board where to place piece
    [currPlayer move]

或者:

// nextPlayer always returns a valid player
while currPlayer := [game nextPlayer]:
    // player's method returns what and where to place
    [self place:[currPlayer move] for:currPlayer]
    // explicitly test for game end, which includes wins & ties
    if [game isOver]:
        break
于 2009-12-29T03:48:20.713 回答