我在C#中创建一个服务器,我有一个处理数组中所有登录用户的单例。该数组是一个名为UserSession的类的数组。
此UserSession类有一个在单独的线程上运行的方法,该线程处理该用户的传入数据包。
好吧,请考虑以下代码:
class UserSession
{
public UserSession(TcpClient client)
{
var thread = new Thread(new ParameterizedThreadStart(HandleComm);
thread.Start((object)client);
}
public void HandleComm(object tcpClient)
{
TcpClient client = (TcpClient)tcpClient;
NetworkStream stream = client.GetStream();
while(1 == 1)
{
byte[] buffer = new byte[4096];
stream.Read(buffer, 0, buffer.Length);
int testShort = Convert.ToInt32(buffer);
switch((ActionEnum)testShort)
{
case ActionEnum.Something:
// here is my problem!
// do some more parsing of the message
this.DoSomething(SomethingStruct argument); // argument taken from the byte array
break;
case ActionEnum.AnotherSomething:
// the same as before
break;
// and this goes on and on
}
}
}
}
处理所有这些单独的枚举的最佳方法是什么,而不会在该类上重复超过80种方法? (ActionEnum是一个包含当前用户特定操作的枚举)。
我序列化了那个缓冲区,我只是快速编写代码让你有个主意。
答案 0 :(得分:2)
所以:你基本上试图这样做,所以将数字代码转换为方法的调用。
有些事情是您无法获得的,例如自动为您完成此转换。如果您已经传输了方法的名称,则可以使用反射来查找方法,然后调用它。因此,您必须做一些手动工作来建立映射。
您必须决定的是将数字映射到方法的最佳方法。
一种方法是你现在使用的那种方式。这里的映射发生在调度周期内(获取号,翻译,调用)。问题是映射代码掩盖了调度代码。还涉及相当数量的样板代码。
您可以使用Command模式和哈希映射的组合,如下所示:
在设置过程中:
在调度循环中:
对于更灵活的方法,请将数字视为必须处理的消息,并使用模式链责任。
命令模式http://en.wikipedia.org/wiki/Command_pattern
责任链http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern
答案 1 :(得分:1)
一如既往,有很多可能的答案。我在构建客户端/服务器游戏时遇到了这个问题。我开始时有几十个Enums用于操作/事件/消息,然后意识到当你进行大量的操作时它不是很可持续。
所以这就是我粗略地用伪代码做的事情。
NetworkClass
{
RegisterChannel(objUsingChannel,typeOfChannel, callbackForChannel, expectedReturnType){/*...*/};
PushChannelMsg(channelID, dataToSend)
ReceiveMessageFromNetwork(msg){ Read data from network, which also contains channelID, and send it to any matching channelID}
//If there is no channel registered for a data that is received, just ignore it
}
EnemyTurretObject
{
//Register the rotation channel and listen for rotation changes
NetworkClass.RegisterChannel(this, channels.TurretRotated + this.ID, callback=HandleTurretRotated, doubleReturnType)
HandleTurretRotated(double rot)
{ rotate the turret }
}
FriendlyTurretObject
{
//Register two channels that we'll send data across
NetworkClass.RegisterChannel(this, channels.TurretFired + this.ID, callback=null, MissleFiredData)
NetworkClass.RegisterChannel(this, channels.TurretRotated + this.ID, callback=null, doubleDataType)
FireMissle()
{
NetworkClass.PushChannelMsg(channels.TurretFired + this.ID, new MissleFiredData(x,y))
}
RotateTurret()
{
NetworkClass.PushChannelMsg(channels.TurretRotated + this.ID, newTurretRotationValue)
}
}
我基本上避免了大量的Enums,并进行了更广泛的设置,以便每个对象负责它自己的数据,通道等。这是一种更灵活的方法,改变一个枚举不会破坏一切。网络类甚至不需要知道正在发送的数据中的内容,它现在只是一个管道。