我正在研究我的小游戏项目,作为学习和实践C的一种方式,我遇到了一个设计问题。假设我们有以下一组类:
interface IGameState
{
//Updates the state and returns next active state
//(Probably itself or a new one)
IGameState Tick();
}
class Game
{
public Game(IGameState initialState)
{
activeState = initialState;
}
public void Tick()
{
activeState = activeState.Tick();
}
IGameState activeState;
}
游戏基本上是游戏状态的状态机。我们可以
MainMenuState
,
LoadingState
或
SinglePlayingState
。但是添加
MultiplayerState
(表示玩多人游戏)需要一个插座连接到服务器:
class MultiplayerState : IGameState, IDisposable
{
public IGameState Tick()
{
//Game logic...
//Communicate with the server using the Socket
//Game logic...
//Render the game
return this;//Or something else if the player quits
}
public void Dispose()
{
server.Dispose();
}
//Long-living, cannot be in method-scope
Socket server;//Or similar network resource
}
好吧,这是我的问题,我不能把它传给
Game
因为它不知道应该处理掉它,而调用代码不容易知道游戏何时不再需要它。这个类设计几乎正是我到目前为止实现的,我可以添加
IDisposable
到
IGameState
但我认为它毕竟不是一个好的设计选择
依甲氨基甲酸盐
S拥有资源。此外,该状态机在某种意义上是动态的,任何活动的
依甲氨基甲酸盐
可以返回新状态。所以
游戏
真的不知道哪一个是一次性的,哪一个是一次性的,所以它只需要测试所有的东西。
所以我问了几个问题:
-
如果我有一个类声明对非密封类型(例如
initialState
在游戏中)我应该一直假设
可识别
?(可能没有)
-
如果我有
可识别
例如,我是否应该放弃它的所有权,将其强制转换为不实现的基础
可识别
?(可能没有)
我从中了解到
可识别
感觉像一个非常独特的界面
有损的
(*)语义-它关心自己的生命周期。这似乎与提供有保证但不确定的内存管理的GC本身的思想直接冲突。我来自C++背景,所以它真的感觉到它试图实现RAII概念,但是只要有0个引用,就可以手动调用Debug(析构函数)。我不是说这是对C的咆哮,更像是我缺少了一些语言特性吗?或者可能是特定于C的模式?我知道有
using
但这只是方法范围。下一个是终结器,它可以确保调用Dispose,但仍然是不确定的,还有其他什么吗?也许像C++一样自动引用计数
shared_ptr
?
正如我所说,上面的例子可以通过不同的设计来解决(但我认为不应该),但不能回答那些可能无法解决的情况,所以请不要太关注它。理想情况下,我希望看到解决类似问题的一般模式。
(*)对不起,也许不是个好词。但我的意思是很多接口表示一种行为,如果类实现了所说的接口,它只会说“嘿,我可以
也
做这些事情,但如果你忽视我的那一部分,我仍然工作得很好”。忘记
可识别
不是
无损
.
我发现了
question
这表明,IDisposable可以通过组合传播,也可以通过继承传播。这对我来说似乎是正确的,需要更多的打字,但是好的。这就是
多层状态
感染了。但在我的例子中
游戏
它还想向上游扩散,这感觉不太对劲。
最后一个问题可能是是否应该有
有损的
接口,比如它是否是工作的正确工具,在这种情况下是什么?或者有其他常用的
有损的
我知道的界面应该是什么?