Arm*_*yan 11 c++ language-agnostic oop design-patterns
我正在为自己的乐趣和训练设计一款小游戏.游戏的真实身份与我的实际问题完全无关,假设它是Mastermind游戏(它实际上是:)
我的真正目标是拥有一个IPlayer可用于任何玩家的界面:计算机或人,控制台或gui,本地或网络.我也打算有一个GameController,它只处理两个IPlayers.
IPlayer接口看起来像这样:
class IPlayer
{
public:
//dtor
virtual ~IPlayer()
{
}
//call this function before the game starts. In subclasses,
//the overriders can, for example, generate and store the combination.
virtual void PrepareForNewGame() = 0;
//make the current guess
virtual Combination MakeAGuess() = 0;
//return false if lie is detected.
virtual bool ProcessResult(Combination const &, Result const &) = 0;
//Answer to opponent's guess
virtual Result AnswerToOpponentsGuess(Combination const&) = 0;
};
Run Code Online (Sandbox Code Playgroud)
GameController类会做这样的事情:
IPlayer* pPlayer1 = PlayerFactory::CreateHumanPlayer();
IPlayer* pPlayer1 = PlayerFactory::CreateCPUPlayer();
pPlayer1->PrepareForNewGame();
pPlayer2->PrepareForNewGame();
while(no_winner)
{
Guess g = pPlayer1->MakeAguess();
Result r = pPlayer2->AnswerToOpponentsGuess(g);
bool player2HasLied = ! pPlayer1->ProcessResult(g, r);
etc.
etc.
}
Run Code Online (Sandbox Code Playgroud)
通过这种设计,我愿意让GameController类不可变,也就是说,我把游戏规则填入其中,而不是其他任何东西,所以既然游戏本身已经建立,那么这个类就不应该改变.对于控制台游戏,这种设计可以完美地运行.我会HumanPlayer,它在其MakeAGuess方法中将从Combination标准输入读取a ,和a CPUPlayer,它会以某种方式随机生成它等.
现在这是我的问题:IPlayer界面和GameController类一起本质上是同步的.我无法想象GameController当我必须等待的MakeAGuess方法(GUIHumanPlayer例如,一些鼠标移动和点击)时,我将如何实现游戏的GUI变体.当然,我可以启动一个等待用户输入的新线程,而主线程会阻塞,以便模仿同步IO,但不知怎的,这个想法让我感到厌恶.或者,或者,我可以将控制器和播放器设计为异步.在这种情况下,对于控制台游戏,我将不得不模仿异步,这似乎比第一个版本更容易.
您是否愿意评论我的设计以及我对选择同步或异步设计的担忧?另外,我觉得我对玩家类的责任比GameController类更多.等等
非常感谢你提前.
PS我不喜欢我的问题的标题.随意编辑:)
Fre*_*abe 11
不要使用各种IPlayer方法的返回值,而是考虑为IPlayer对象引入一个观察者类,如下所示:
class IPlayerObserver
{
public:
virtual ~IPlayerObserver() { }
virtual void guessMade( Combination c ) = 0;
// ...
};
class IPlayer
{
public:
virtual ~IPlayer() { }
virtual void setObserver( IPlayerObserver *observer ) = 0;
// ...
};
Run Code Online (Sandbox Code Playgroud)
的方法,IPlayer那么应该调用的安装适当的方法IPlayerObserver,而不是返回一个值,如:
void HumanPlayer::makeAGuess() {
// get input from human
Combination c;
c = ...;
m_observer->guessMade( c );
}
Run Code Online (Sandbox Code Playgroud)
然后,您的GameController类可以实现,IPlayerObserver以便在玩家做一些有趣的事情时得到通知,例如 - 猜测.
使用这种设计,如果所有IPlayer方法都是异步的,那就完全没问题了.事实上,这是可以预期的 - 它们都会回归void!您的游戏控制器会调用makeAGuess活动播放器(这可能会立即计算结果,或者它可能会为多人游戏做一些网络IO,或者它会等待GUI执行某些操作)并且每当玩家做出他的选择时,游戏控制器就可以请放心,该guessMade方法将被调用.此外,玩家对象仍然不知道游戏控制器的任何信息.他们只是在处理一个不透明的'IPlayerObserver'接口.
| 归档时间: |
|
| 查看次数: |
858 次 |
| 最近记录: |