我正在WPF中实现一个事件驱动的游戏,并有以下Blackjack类:
public class Blackjack
{
public Dealer Dealer { get; } = new Dealer();
public Player Player { get; } = new Player();
public IList<Player> AiPlayers { get; } = new List<Player>();
public event EventHandler<EventArgs>? NewGameStarted;
public event EventHandler<EventArgs>? HandStarted;
public event EventHandler<GameOverEventArgs>? HandEnded;
public Blackjack()
{
Dealer.Hand.Busted += DealerBusted;
Player.BetPlaced += BetPlaced;
Player.PlayerHit += PlayerHit;
Player.PlayerStand += PlayerStand;
Player.Hand.Blackjack += PlayerBlackjack;
Player.Hand.Busted += PlayerBusted;
_gameStates[Player] = GameStates.PLAYING;
}
public void StartNewGame(int numAiPlayers)
{
for (var i = 0; i < numAiPlayers; i++)
{
var ai = new Player();
AiPlayers.Add(ai);
ai.PlayerHit += PlayerHit;
ai.PlayerStand += PlayerStand;
ai.Hand.Blackjack += PlayerBlackjack;
ai.Hand.Busted += PlayerBusted;
_gameStates[ai] = GameStates.PLAYING;
}
OnNewGameStarted(new EventArgs());
}
// More methods
}
但是正如您所看到的,player/ai创建开始污染我的构造函数和StartNewGame
方法。此外,我希望能够使用不同的认可机构来模拟不同的策略。
我想把它搬到一个工厂,但意识到我会订阅工厂内的Blackjack
活动。我觉得很奇怪..。这是一件正常的事情吗?还是最好在我的Blackjack
类中创建处理player/ai创建和连接事件的方法。
发布于 2020-09-04 07:43:24
如果Blackjack对象可以构建不同的方式,那么工厂模式将是有用的。这里似乎不是这样的。您关心需要在构造函数中映射的事件处理程序的数量。那么,简化这些事件如何?
我看到的是好的,事件名称包含有关事件的上下文,每个事件被映射到它的处理程序一对一。
ai.PlayerHit += PlayerHit
如果事件的名称变成了只代表感兴趣的对象的泛型事件的属性,那么会发生什么呢?
ai.OnAction += OnAction
该事件可能包含有关所采取的操作的信息;可用于决定如何处理该事件的信息;您在事件处理程序中编码的内容将成为方法。
class ActionEvent // information about the event
enum PlayerAction
enum PlayerAction // an enumeration containing the player actions
Bet
Hit
Stand
然后,可以在单个事件处理程序中使用if语句。
if(e.PlayerAction = Bet)
PlayBet();
这样,就可以将所有事件减少到一个事件,这样就更容易在构造函数中进行配置。这就像工厂的想法,你现在是决定做什么,而不是如何建设。
希望这是有帮助的。编码愉快。
发布于 2020-04-06 18:04:35
我可能会做这样的事:
/// <summary>
/// Immutable snapshot of a table that you
/// can use to display to players or AIs.
/// </summary>
internal sealed class Table
{
}
/// <summary>
/// Represents a round of the game.
/// </summary>
internal sealed class Round
{
private readonly IEnumerable<Player> players;
public Round(IEnumerable<Player> players)
{
this.players = players;
}
public void RunGame()
{
while (players.Any(t => !t.IsFinished))
{
foreach (var player in players.Where(t => !t.IsFinished).ToArray())
{
var play = player.GetPlay(CurrentTable);
}
}
}
/// <summary>
/// Returns a current snapshot of the table.
/// </summary>
private Table CurrentTable { get; }
private void UpdateState(Player player, Play play)
{
//Update any state needed to make the table.
}
}
/// <summary>
/// Represents a player - implementations for different
/// AIs and for the human player.
/// </summary>
internal abstract class Player
{
public abstract Play GetPlay(Table currentTableState);
public abstract bool IsFinished { get; }
}
/// <summary>
/// Represents the result of a play made by a player.
/// </summary>
internal sealed class Play
{
public bool IsBet { get; }
public bool IsHit { get; }
public bool IsStand { get; }
public decimal Amount { get; }
private Play(bool isBet, bool isHit, bool isStand, decimal amount)
{
IsBet = isBet;
IsHit = isHit;
IsStand = isStand;
Amount = amount;
}
}
在这一点上,游戏指导球员,而不是相反的方式,所以没有必要让游戏听取事件。任何事件都将是人工玩家实现的实现细节。
https://softwareengineering.stackexchange.com/questions/401250
复制相似问题