我该如何组织这段代码?
myThread 是一个每秒执行一次的函数,基本上它会读取一些必须解析和执行的数据。该函数增长了很多,超过 1500 行代码,如下面的示例,其中有很多 [if else if else] 块,阻止大量重复操作,例如 sleep 或 SendToChat 向控制台发送命令,并且维护起来非常困难,对其进行更改等。
我想要一些关于如何重写此代码的建议(如果可能的话,提供代码示例,这将帮助我理解布局),我经验不足,所以我不太确定是否有可能将此代码转换为更好的代码可维护性和可读性 ?
也请随意对任何功能或其他任何事情发表评论,因为它可以帮助我改进其他错误的事情。
这只是代码的一些示例,而不是整个代码,如果您觉得需要代码中的任何其他信息,请随时询问,我会尽快发布。
PS:这不是一个irc 的事情。
private void myThread()
{
while(isRunning)
{
// SOME PARSED DATA HERE
// if (parsedData matchs) do the below stuff
Messages received = new Messages
{
Sent = Convert.ToDateTime(match.Groups[1].Value),
Username = match.Groups[3].Value,
MessageType = (match.Groups[2].Length > 0) ? MsgType.System : MsgType.Chat,
Message = match.Groups[4].Value.Trim(),
CommandArgs = match.Groups[4].Value.ToLower().Trim().Split(' ')
};
// Get the user that issued the command
User user = usersList.Find(x => x.Name == recebe.received.ToLower());
if (user != null)
{
// different greetings based on acess level
if (received.Message == "has entered this room")
{
if (User == null)
{
SendToChat("/w " + received.Username + " " + received.Username + " you have no registration.");
Thread.Sleep(1000);
SendToChat("/kick " + received.Username + " not registered.");
Thread.Sleep(1000);
}
else
{
string cmd = (user.Access < Access.Vouch) ?
"/ann " + user.Access.ToString() + " <" + received.Username + "> has entered the room." :
"/w " + received.Username + " " + received.Username + " welcome to our room !";
SendToChat(cmd);
Thread.Sleep(1000);
}
}
// Here we filter all messages that start with a . which means it is a command
else if (received.Message.StartsWith(".") && user != null)
{
// here we verify if the user has Access to use the typed command and/or if the command exists
if (accessList.Exists(x => x.Access == user.Access && x.HasCommand(received.CommandArgs[0])))
{
if (received.CommandArgs[0] == ".say")
{
SendToChat("/ann " + received.Username + " says: " + received.Message.Substring(received.CommandArgs[0].Length + 1));
Thread.Sleep(1000);
}
else if (received.CommandArgs[0] == ".command")
{
string allowedList = string.Empty;
int count = 0;
foreach (string cmd in listaAccesss.Find(x => x.Access == user.Access).Command)
{
if (count == 0)
allowedList += cmd;
else
allowedList += ", " + cmd;
}
SendToChat("/w " + received.Username + " " + received.Username + " you are allowed to use the followed commands: " + permite);
Thread.Sleep(1000);
}
else if (received.CommandArgs[0] == ".vip")
{
if (received.Command.Count() < 2)
{
SendToChat("/w " + received.Username + " " + received.Username + ", see an example of how to use this command: .vip jonh");
Thread.Sleep(1000);
}
else if (received.Command.Count() == 2)
{
var target = usersList.Find(x => x.Name == received.CommandArgs[1]);
if (target == null)
{
User newUser = new User
{
Name = received.CommandArgs[1].ToLower(),
Access = Access.VIP,
Registered = DateTime.Now,
RegisteredBy = received.Username.ToLower()
};
usersList.Add(newUser);
SendToChat("/ann " + user.Access.ToString() + " " + user.Name + " has promoted " + received.CommandArgs[1] + " to VIP.");
Thread.Sleep(1000);
}
else if (target != null && target.Access == Access.VIP)
{
SendToChat("/w " + received.Username + " " + received.Username + " the user " + target.Name + " already have VIP access.");
Thread.Sleep(1000);
}
else if (target != null && user.Access == Access.HeadAdmin && user.Access < target.Access)
{
Access last = target.Access;
target.Access = Access.Vouch;
SendToChat("/ann " + user.Access.ToString() + " " + received.Username + " promoted/demoted the " + last.ToString() + " " + target.Name + " to VIP.");
Thread.Sleep(1000);
}
else if (target != null && target.Access == Access.Vouch)
{
target.Access = Access.VIP;
target.RegisteredBy = user.Name;
SendToChat("/ann " + user.Access.ToString() + " " + received.Username + " promoted the vouch of " + target.Name + " to VIP.");
Thread.Sleep(1000);
}
else
{
SendToChat("/w " + received.Username + " " + received.Username + " you can't register or modify the user " + received.CommandArgs[1] + ".");
Thread.Sleep(1000);
}
}
}
}
else
{
SendToChat("/w " + received.Username + " " + received.Username + " command not found.");
Thread.Sleep(1000);
}
}
}
Thread.Sleep(1000);
}
}
myThread is a function that is executed every second, basicly it reads some data that has to be parsed and executed. The function grew a lot and it is over 1500 lines of code like the sample below with lots of [if else if else] blocks lots of repetitions like sleep or SendToChat to send a command to the console, and its being a lot difficult to maintain, make changes, etc, to it.
I would like some advices (if possible with code examples, that would help me understand the layout) on how I could rewrite this, I am not very experienced so I am not so sure of the possibilities to turn this code into a better code for maintainability and readability ?
Also feel free to comment on any functions or anything else as it could help me improve on other things that are wrong.
This is just some sample of the code and not the entire code if you feel like you need any other information from the code feel free to ask and I will post once I can.
PS: this is not an irc thing.
private void myThread()
{
while(isRunning)
{
// SOME PARSED DATA HERE
// if (parsedData matchs) do the below stuff
Messages received = new Messages
{
Sent = Convert.ToDateTime(match.Groups[1].Value),
Username = match.Groups[3].Value,
MessageType = (match.Groups[2].Length > 0) ? MsgType.System : MsgType.Chat,
Message = match.Groups[4].Value.Trim(),
CommandArgs = match.Groups[4].Value.ToLower().Trim().Split(' ')
};
// Get the user that issued the command
User user = usersList.Find(x => x.Name == recebe.received.ToLower());
if (user != null)
{
// different greetings based on acess level
if (received.Message == "has entered this room")
{
if (User == null)
{
SendToChat("/w " + received.Username + " " + received.Username + " you have no registration.");
Thread.Sleep(1000);
SendToChat("/kick " + received.Username + " not registered.");
Thread.Sleep(1000);
}
else
{
string cmd = (user.Access < Access.Vouch) ?
"/ann " + user.Access.ToString() + " <" + received.Username + "> has entered the room." :
"/w " + received.Username + " " + received.Username + " welcome to our room !";
SendToChat(cmd);
Thread.Sleep(1000);
}
}
// Here we filter all messages that start with a . which means it is a command
else if (received.Message.StartsWith(".") && user != null)
{
// here we verify if the user has Access to use the typed command and/or if the command exists
if (accessList.Exists(x => x.Access == user.Access && x.HasCommand(received.CommandArgs[0])))
{
if (received.CommandArgs[0] == ".say")
{
SendToChat("/ann " + received.Username + " says: " + received.Message.Substring(received.CommandArgs[0].Length + 1));
Thread.Sleep(1000);
}
else if (received.CommandArgs[0] == ".command")
{
string allowedList = string.Empty;
int count = 0;
foreach (string cmd in listaAccesss.Find(x => x.Access == user.Access).Command)
{
if (count == 0)
allowedList += cmd;
else
allowedList += ", " + cmd;
}
SendToChat("/w " + received.Username + " " + received.Username + " you are allowed to use the followed commands: " + permite);
Thread.Sleep(1000);
}
else if (received.CommandArgs[0] == ".vip")
{
if (received.Command.Count() < 2)
{
SendToChat("/w " + received.Username + " " + received.Username + ", see an example of how to use this command: .vip jonh");
Thread.Sleep(1000);
}
else if (received.Command.Count() == 2)
{
var target = usersList.Find(x => x.Name == received.CommandArgs[1]);
if (target == null)
{
User newUser = new User
{
Name = received.CommandArgs[1].ToLower(),
Access = Access.VIP,
Registered = DateTime.Now,
RegisteredBy = received.Username.ToLower()
};
usersList.Add(newUser);
SendToChat("/ann " + user.Access.ToString() + " " + user.Name + " has promoted " + received.CommandArgs[1] + " to VIP.");
Thread.Sleep(1000);
}
else if (target != null && target.Access == Access.VIP)
{
SendToChat("/w " + received.Username + " " + received.Username + " the user " + target.Name + " already have VIP access.");
Thread.Sleep(1000);
}
else if (target != null && user.Access == Access.HeadAdmin && user.Access < target.Access)
{
Access last = target.Access;
target.Access = Access.Vouch;
SendToChat("/ann " + user.Access.ToString() + " " + received.Username + " promoted/demoted the " + last.ToString() + " " + target.Name + " to VIP.");
Thread.Sleep(1000);
}
else if (target != null && target.Access == Access.Vouch)
{
target.Access = Access.VIP;
target.RegisteredBy = user.Name;
SendToChat("/ann " + user.Access.ToString() + " " + received.Username + " promoted the vouch of " + target.Name + " to VIP.");
Thread.Sleep(1000);
}
else
{
SendToChat("/w " + received.Username + " " + received.Username + " you can't register or modify the user " + received.CommandArgs[1] + ".");
Thread.Sleep(1000);
}
}
}
}
else
{
SendToChat("/w " + received.Username + " " + received.Username + " command not found.");
Thread.Sleep(1000);
}
}
}
Thread.Sleep(1000);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
通常,当您看到复杂的条件逻辑(大量 if/else 块和嵌套条件)时,您应该考虑将代码重构为 状态或策略设计模式(取决于具体情况)。看看这些以获得一些想法。
更新:
如果您在如何重构代码方面遇到困难,我最近读了一本很棒的书,它可以帮助分解该过程(涵盖从添加版本控制,到单元测试,到持续集成的所有内容......还讨论了打破事物迭代下来,直到您能够应用诸如依赖注入等之类的东西)。它没有完全深入地涵盖任何主题,因为有专门针对每个主题的整本书,但这是一个很好的起点:
.Net 中的棕地应用程序开发
Often when you see complicated conditional logic (lots of if/else blocks and nested conditions), you should consider refactoring your code into the State or Strategy design patterns (depends on the situation). Have a look at those for some ideas.
UPDATE:
If you're having trouble on how to refactor your code, there is a great book I read recently that helps break the process down (covers everything from adding version control, to unit testing, to continuous integration... also talks about breaking things down iteratively until you are able to apply things like dependency injection etc.). It doesn't cover any of the topics in complete depth, because there are entire books dedicated to each individual subject, but it's a great starting point:
Brownfield Application Development in .Net
组织此代码的一个好方法是使用“责任链”设计图案。
这个想法是为每个“命令”创建一个知道要做什么的类,例如:
每个命令都需要这些类之一。
A good way to organize this code is by using the "Chain of responsibility" design pattern.
The idea is to have one class for each "command" that knows what to do, for example:
You will need one of these classes for every command.
我通常会使用一个小技巧,虽然这不是一个好的重构方法,但可以使代码更具可读性。
而不是:
... 我使用:
降低代码的复杂性是分解代码的第一步。我接下来要采取的步骤是:
I usually make a little trick that, while is not a good method of refactoring, makes the code more readable.
Instead of having:
... I use:
Reducing the complexity of the code is the first step to break it apart. Next steps in order for me to take are:
它肯定需要一些重构。有几件事:
)
It definitely needs some refactoring. A few things:
)
好吧,一开始,我认为你应该将这个巨大的代码分成几个方法。将您评论过的逻辑部分分开。您应该为评论的每个部分使用一种方法(这是最少的)。尝试开始这个:
Method: // SOME PARSED DATA HERE
// if (parsedData matches) 执行以下操作
尝试为此创建一种方法。
Method // 获取发出命令的用户
Method // 基于访问级别的不同问候语
Method // 这里我们过滤所有以 .这意味着它是一个命令
等等...
并且您必须创建重复的部分方法,以便您可以始终在一个地方进行更改,而不是搜索所有代码并将每个参数更改为新值。
Well, for the beginning, i think you should split this huge code into several methods. To separate this logical parts that you have commented. You should have one method for each part of comment (that's minimum). Try for beginning this:
Method: // SOME PARSED DATA HERE
// if (parsedData matchs) do the below stuff
Try to make one method of this.
Method // Get the user that issued the command
Method // different greetings based on acess level
Method // Here we filter all messages that start with a . which means it is a command
and so on...
And you MUST make methods of parts that repeat so you can make changes always on just one place, not to search throught all code and change every parameter to new value.