如何安全地覆盖方法
How to override methods safely
我有一个摘要 class 为 child classes 做了很多艰苦的工作。
每个虚拟方法都有一些验证规则。
protected virtual void PrepareToStartGame(TimeSpan remainingTime, GameStarted response)
{
if (IsGameActive != true)
{
Debug.LogError("There isn't an active game!");
return;
}
if (gameStarted)
{
Debug.LogError("Game is already started!");
return;
}
if (preparedForStart)
{
Debug.LogError("Game is already prepared to start");
return;
}
if (RoomId != response.Game.RoomId)
{
Debug.LogError("Wrong GameStarted RoomId!");
return;
}
...
}
现在,无论何时重写此方法,我都应该能够安全地重写它。例如,这个覆盖有一个错误,因为它不检查验证规则:
protected override void PrepareToStartGame(TimeSpan remainingTime, GameStarted response)
{
base.PrepareToStartGame(remainingTime, response);
WaitingForPlayersPanel.gameObject.SetActive(false);
}
我正在考虑解决此问题的方法,它可以帮助我在将来不用担心此类错误。
你对此有何建议?
我知道我可以 return 一个 bool 表示成功或创建一个验证方法来检查每个被覆盖的方法。但我正在寻找更好的解决方案。
在一些有效的情况下,来自服务器的一些事件可能会导致错误的方法调用,所以我不能在这里抛出异常,应该忽略它们。
您可以“反转”依赖关系(基本上实现 template method),使此方法成为非虚拟方法并引入一个新方法:
protected void PrepareToStartGame(TimeSpan remainingTime, GameStarted response)
{
if (IsGameActive != true)
{
Debug.LogError("There isn't an active game!");
return;
}
if (gameStarted)
{
Debug.LogError("Game is already started!");
return;
}
if (preparedForStart)
{
Debug.LogError("Game is already prepared to start");
return;
}
if (RoomId != response.Game.RoomId)
{
Debug.LogError("Wrong GameStarted RoomId!");
return;
}
...
PrepareToStartGameInner(remainingTime, response);
}
protected virtual void PrepareToStartGameInner(remainingTime, response) {};
并且在 child class:
protected override void PrepareToStartGameInner(TimeSpan remainingTime, GameStarted response)
{
WaitingForPlayersPanel.gameObject.SetActive(false);
}
我会说,如果你想通知验证错误,你应该从方法中抛出自定义错误。调用者应根据工作流要求优雅地处理它。
当您不想将控制权交给继承的方法时,请不要将其声明为虚拟的或可重写的。
当您想给予部分控制权时,引发事件而不是使方法虚拟或可重写。继承的 class 然后可以处理事件而不是覆盖方法。如果他们不需要,他们总是可以选择不处理事件。
例如
public event EventHandler PreparingToStartGame;
public event EventHandler PreparedToStartGame;
protected void OnPrepareToStartGame(TimeSpan remainingTime, GameStarted response)
{
PreparingToStartGame?.Invoke(this, new EventArgs());
if (IsGameActive != true)
{
Debug.LogError("There isn't an active game!");
return;
}
if (gameStarted)
{
Debug.LogError("Game is already started!");
return;
}
if (preparedForStart)
{
Debug.LogError("Game is already prepared to start");
return;
}
if (RoomId != response.Game.RoomId)
{
Debug.LogError("Wrong GameStarted RoomId!");
return;
}
//......
PreparedToStartGame?.Invoke(this, new EventArgs());
}
我使用 new EventArgs()
只是为了上面的演示。但是你可以创建一个 class 继承自 EventArgs 并使用它来代替,如果你想 give/take 参数值 to/from 方法。
HTH.
我有一个摘要 class 为 child classes 做了很多艰苦的工作。
每个虚拟方法都有一些验证规则。
protected virtual void PrepareToStartGame(TimeSpan remainingTime, GameStarted response)
{
if (IsGameActive != true)
{
Debug.LogError("There isn't an active game!");
return;
}
if (gameStarted)
{
Debug.LogError("Game is already started!");
return;
}
if (preparedForStart)
{
Debug.LogError("Game is already prepared to start");
return;
}
if (RoomId != response.Game.RoomId)
{
Debug.LogError("Wrong GameStarted RoomId!");
return;
}
...
}
现在,无论何时重写此方法,我都应该能够安全地重写它。例如,这个覆盖有一个错误,因为它不检查验证规则:
protected override void PrepareToStartGame(TimeSpan remainingTime, GameStarted response)
{
base.PrepareToStartGame(remainingTime, response);
WaitingForPlayersPanel.gameObject.SetActive(false);
}
我正在考虑解决此问题的方法,它可以帮助我在将来不用担心此类错误。
你对此有何建议?
我知道我可以 return 一个 bool 表示成功或创建一个验证方法来检查每个被覆盖的方法。但我正在寻找更好的解决方案。
在一些有效的情况下,来自服务器的一些事件可能会导致错误的方法调用,所以我不能在这里抛出异常,应该忽略它们。
您可以“反转”依赖关系(基本上实现 template method),使此方法成为非虚拟方法并引入一个新方法:
protected void PrepareToStartGame(TimeSpan remainingTime, GameStarted response)
{
if (IsGameActive != true)
{
Debug.LogError("There isn't an active game!");
return;
}
if (gameStarted)
{
Debug.LogError("Game is already started!");
return;
}
if (preparedForStart)
{
Debug.LogError("Game is already prepared to start");
return;
}
if (RoomId != response.Game.RoomId)
{
Debug.LogError("Wrong GameStarted RoomId!");
return;
}
...
PrepareToStartGameInner(remainingTime, response);
}
protected virtual void PrepareToStartGameInner(remainingTime, response) {};
并且在 child class:
protected override void PrepareToStartGameInner(TimeSpan remainingTime, GameStarted response)
{
WaitingForPlayersPanel.gameObject.SetActive(false);
}
我会说,如果你想通知验证错误,你应该从方法中抛出自定义错误。调用者应根据工作流要求优雅地处理它。
当您不想将控制权交给继承的方法时,请不要将其声明为虚拟的或可重写的。
当您想给予部分控制权时,引发事件而不是使方法虚拟或可重写。继承的 class 然后可以处理事件而不是覆盖方法。如果他们不需要,他们总是可以选择不处理事件。
例如
public event EventHandler PreparingToStartGame;
public event EventHandler PreparedToStartGame;
protected void OnPrepareToStartGame(TimeSpan remainingTime, GameStarted response)
{
PreparingToStartGame?.Invoke(this, new EventArgs());
if (IsGameActive != true)
{
Debug.LogError("There isn't an active game!");
return;
}
if (gameStarted)
{
Debug.LogError("Game is already started!");
return;
}
if (preparedForStart)
{
Debug.LogError("Game is already prepared to start");
return;
}
if (RoomId != response.Game.RoomId)
{
Debug.LogError("Wrong GameStarted RoomId!");
return;
}
//......
PreparedToStartGame?.Invoke(this, new EventArgs());
}
我使用 new EventArgs()
只是为了上面的演示。但是你可以创建一个 class 继承自 EventArgs 并使用它来代替,如果你想 give/take 参数值 to/from 方法。
HTH.