当您发现自己需要按特定顺序执行事件时的 C# 设计模式
C# design pattern when you find yourself in need of events to be executed in specific order
我正在用 C# 制作一个游戏,当玩家移动时,两个不同的 class 会通过事件得到通知。
其中一个 class 是 RenderGrid
,一旦玩家移动,RenderGrid 将仅实例化现在在屏幕上可见的新游戏图块。它还包含两个向量,描述当前正在渲染的网格的左下角和右上角
另一个是 WorldManager
class,一旦玩家移动,它就会检查是否需要加载和创建游戏世界的新区块。为此,它需要检查 RenderGrid
的角以确保它们仍在已加载块的边界内。
这就是问题所在,因为 WorldManager
取决于 事件首先在 RenderGrid
上处理,然后在 WorldManager
上处理,因此中断事件模式
在伪代码中,这里是 RenderGrid:
public class RenderGrid
{
public Vector2 bottomLeft;
public Vector2 topRight;
public RenderGrid()
{
Player.onPlayerMoved += playerMoved;
}
~RenderGrid()
{
Player.onPlayerMoved -= playerMoved;
}
private void playerMoved(Vector2 delta, Vector2 position)
{
// updates the bottomLeft and topRight corners
}
}
和 WorldGrid:
public class WorldGrid
{
public WorldGrid()
{
Player.onPlayerMoved += playerMoved;
}
~WorldGrid()
{
Player.onPlayerMoved -= playerMoved;
}
private void playerMoved(Vector2 delta, Vector2 position)
{
// it needs the corners of the renderGrid, but since those are also updated when player moves, we can't be sure
// wheter they've been updated here or not
}
}
使用单独的事件通知 RenderGrid
角落已更新,听着好像是意大利面,我不确定如何从这里开始
除了 SO 上关于事件顺序是否得到保证的传奇争议:
问问自己,谁对事件的响应责任最大,那么这个应该先响应。在此基础上,在 WorldGrid 和 RenderGrid 之间注册另一个事件(具有不同的名称)有什么问题?
如果 RenderGrid 归 WorldGrid 所有,反之亦然,您甚至可以定义并调用 RenderGrid.NotifyContentLoaded 或 WorldGrid.NotifyBordersChanged.
链接事件
似乎 RenderGrid
应该处理指示玩家移动的事件。 RenderGrid
然后可以发布自己的事件。 WorldGrid
会订阅这些事件,因此它只会在 Rendergrid 完成处理后触发。
典型的模式是设置自定义事件参数、委托和处理程序,如下所示:
自定义事件参数,处理程序委托:
public class PlayerMovedEventArgs
{
public Vector2 Delta { get; set; }
public Vector2 Position { get; set; }
}
public delegate void PlayerMovedHandler(object sender, PlayerMovedEventArgs e);
然后是渲染网格:
public class RenderGrid
{
public Vector2 bottomLeft;
public Vector2 topRight;
public Player _player;
public event PlayerMovedHandler Changed;
public RenderGrid(Player player)
{
_player = player;
_player.OnPlayerMoved += PlayerMovedInGrid;
}
private void UpdateCorners(Vector2 delta, Vector2 position)
{
//ToDo: Update corners
}
private void PlayerMovedInGrid(object sender, PlayerMovedEventArgs e)
{
UpdateCorners(e.Delta, e.Position);
OnChanged(e);
}
protected void OnChanged(PlayerMovedEventArgs e)
{
if (Changed != null) Changed(this, e);
}
}
最后是 WorldGrid。这里的重要变化是 WorldGrid 订阅了 RenderGrid 的事件(不是 Player 的)。
public class WorldGrid
{
private readonly Player _player;
private readonly RenderGrid _renderGrid;
public WorldGrid(Player player, RenderGrid renderGrid)
{
_player = player;
_renderGrid = renderGrid;
_renderGrid.Changed += this.PlayerMovedInWorld;
}
private void PlayerMovedInWorld(object sender, PlayerMovedEventArgs e)
{
// it needs the corners of the renderGrid, but since those are also updated when player moves, we can't be sure
// wheter they've been updated here or not
}
}
我正在用 C# 制作一个游戏,当玩家移动时,两个不同的 class 会通过事件得到通知。
其中一个 class 是 RenderGrid
,一旦玩家移动,RenderGrid 将仅实例化现在在屏幕上可见的新游戏图块。它还包含两个向量,描述当前正在渲染的网格的左下角和右上角
另一个是 WorldManager
class,一旦玩家移动,它就会检查是否需要加载和创建游戏世界的新区块。为此,它需要检查 RenderGrid
的角以确保它们仍在已加载块的边界内。
这就是问题所在,因为 WorldManager
取决于 事件首先在 RenderGrid
上处理,然后在 WorldManager
上处理,因此中断事件模式
在伪代码中,这里是 RenderGrid:
public class RenderGrid
{
public Vector2 bottomLeft;
public Vector2 topRight;
public RenderGrid()
{
Player.onPlayerMoved += playerMoved;
}
~RenderGrid()
{
Player.onPlayerMoved -= playerMoved;
}
private void playerMoved(Vector2 delta, Vector2 position)
{
// updates the bottomLeft and topRight corners
}
}
和 WorldGrid:
public class WorldGrid
{
public WorldGrid()
{
Player.onPlayerMoved += playerMoved;
}
~WorldGrid()
{
Player.onPlayerMoved -= playerMoved;
}
private void playerMoved(Vector2 delta, Vector2 position)
{
// it needs the corners of the renderGrid, but since those are also updated when player moves, we can't be sure
// wheter they've been updated here or not
}
}
使用单独的事件通知 RenderGrid
角落已更新,听着好像是意大利面,我不确定如何从这里开始
除了 SO 上关于事件顺序是否得到保证的传奇争议:
问问自己,谁对事件的响应责任最大,那么这个应该先响应。在此基础上,在 WorldGrid 和 RenderGrid 之间注册另一个事件(具有不同的名称)有什么问题?
如果 RenderGrid 归 WorldGrid 所有,反之亦然,您甚至可以定义并调用 RenderGrid.NotifyContentLoaded 或 WorldGrid.NotifyBordersChanged.
链接事件
似乎 RenderGrid
应该处理指示玩家移动的事件。 RenderGrid
然后可以发布自己的事件。 WorldGrid
会订阅这些事件,因此它只会在 Rendergrid 完成处理后触发。
典型的模式是设置自定义事件参数、委托和处理程序,如下所示:
自定义事件参数,处理程序委托:
public class PlayerMovedEventArgs
{
public Vector2 Delta { get; set; }
public Vector2 Position { get; set; }
}
public delegate void PlayerMovedHandler(object sender, PlayerMovedEventArgs e);
然后是渲染网格:
public class RenderGrid
{
public Vector2 bottomLeft;
public Vector2 topRight;
public Player _player;
public event PlayerMovedHandler Changed;
public RenderGrid(Player player)
{
_player = player;
_player.OnPlayerMoved += PlayerMovedInGrid;
}
private void UpdateCorners(Vector2 delta, Vector2 position)
{
//ToDo: Update corners
}
private void PlayerMovedInGrid(object sender, PlayerMovedEventArgs e)
{
UpdateCorners(e.Delta, e.Position);
OnChanged(e);
}
protected void OnChanged(PlayerMovedEventArgs e)
{
if (Changed != null) Changed(this, e);
}
}
最后是 WorldGrid。这里的重要变化是 WorldGrid 订阅了 RenderGrid 的事件(不是 Player 的)。
public class WorldGrid
{
private readonly Player _player;
private readonly RenderGrid _renderGrid;
public WorldGrid(Player player, RenderGrid renderGrid)
{
_player = player;
_renderGrid = renderGrid;
_renderGrid.Changed += this.PlayerMovedInWorld;
}
private void PlayerMovedInWorld(object sender, PlayerMovedEventArgs e)
{
// it needs the corners of the renderGrid, but since those are also updated when player moves, we can't be sure
// wheter they've been updated here or not
}
}