我正在为iOS开发BlackJack游戏。跟踪当前状态和需要完成的工作变得困难。例如,我有一个跟踪当前游戏的C ++类:
class Game {
queue<Player> playerQueue;
void hit();
void stand();
}
目前我正在使用事件(方法A)来实现它:
- (void)hitButtonPress:(id)sender {
game->hit();
}
void Game::hit() {
dealCard(playerQueue.top());
}
void Game::stand() {
playerQueue.pop();
goToNextPlayersTurn();
}
随着越来越多的选项被添加到游戏中,为每个选项创建事件变得乏味且难以跟踪。
我想实现它的另一种方式就是这样(方法B):
void Game::playersTurn(Player *player) {
dealCards(player);
while (true) {
string choice = waitForUserChoice();
if (choice == "stand") break;
if (choice == "hit")
dealCard(player);
// etc.
}
playerQueue.pop();
goToNextPlayersTurn();
}
其中waitForUserChoice
是一个允许用户与UIViewController
交互的特殊函数,一旦用户按下按钮,则只有控件返回playersTurn
函数。换句话说,它会暂停程序直到用户点击按钮。
使用方法A,我需要在每次需要用户交互时拆分我的功能。方法B让一切都保持控制。 基本上方法A和B之间的区别如下:
A:
function A() {
initialize();
// now wait for user interaction by waiting for a call to CompleteA
}
function CompleteA() {
finalize();
}
B:
function B() {
initialize();
waitForUserInteraction();
finalize();
}
注意B如何使代码更有条理。有没有办法用Objective-C做到这一点?或者是否有一种我没有提到的不同方法呢?
我能想到的第三个选择是使用有限状态机。我听过一些关于它们的内容,但我确定在这种情况下是否能帮助我。
我的问题的推荐设计模式是什么?
答案 0 :(得分:1)
我理解你遇到的两难困境。当我第一次启动iOS时,我很难绕过放弃对操作系统的控制。
一般情况下iOS会鼓励你使用方法A.通常你在ViewController中有变量,它们在方法A()中设置,然后在CompleteA()中检查它们以验证A()是否先运行等。
关于有限状态机的问题,我认为它可以帮助您解决问题。我在iOS编写的第一件事是FSM(这是非常糟糕的代码)但是你可以看看这里(靠近FlipsideViewController.m的底部:
https://github.com/esromneb/ios-finite-state-machine
一般的想法是你将它放在@interface块中的.h文件中
static int state = 0;
static int running = 0;
在你的.m中你有这个:
- (void) tick {
switch (state) {
case 0:
//this case only runs once for the fsm, so setup one time initializations
// next state
state = 1;
break;
case 1:
navBarStatus.topItem.title = @"Connecting...";
state = 2;
break;
case 2:
// if something happend we move on, if not we wait in the connecting stage
if( something )
state = 3;
else
state = 1;
break;
case 3:
// respond to something
// next state
state = 4;
break;
case 4:
// wait for user interaction
navBarStatus.topItem.title = @"Press a button!";
state = 4;
globalCommand = userInput;
// if user did something
if( globalCommand != 0 )
{
// go to state to consume user interaction
state = 5;
}
break;
case 5:
if( globalCommand == 6 )
{
// respond to command #6
}
if( globalCommand == 7 )
{
// respond to command #7
}
// go back and wait for user input
state = 4;
break;
default:
state = 0;
break;
}
if( running )
{
[self performSelector:@selector(tick) withObject:nil afterDelay:0.1];
}
}
在这个例子中(从github上的一个修改),globalCommand是一个表示用户输入的int。如果globalCommand为0,则FSM仅在状态4中旋转,直到globalCommand为非零。
要启动FSM,只需将running设置为1并从viewController调用[self tick]。 FSM将每0.1秒“勾选”一次,直到运行设置为0。
在我最初的FSM设计中,我不得不从运行它自己的软件的Windows计算机响应用户输入和网络输入。在我的设计中,Windows PC也运行了类似但不同的FSM。对于这种设计,我使用NSMutuableArray构建了两个命令的FIFO队列对象。用户交互和网络数据包会将命令排入队列,而FSM会将项目出列并对其进行响应。我最终使用https://github.com/esromneb/ios-queue-object作为队列。
如果您需要任何澄清,请发表评论。