我该如何组织这段代码?

发布于 2024-11-10 06:25:01 字数 6957 浏览 5 评论 0原文

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

赴月观长安 2024-11-17 06:25:01

通常,当您看到复杂的条件逻辑(大量 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

若沐 2024-11-17 06:25:01

组织此代码的一个好方法是使用“责任链”设计图案。

这个想法是为每个“命令”创建一个知道要做什么的类,例如:

public class NewUserCommand : ConsoleCommand
{
    public override void Process(Context context, string command)
    {
        if (context.User != null)
        {
            // different greetings based on acess level
            if (context.Received.Message == "has entered this room")
            {
                if (context.User == null)
                {
                    SendToChat("/w " + context.Received.Username + " " + context.Received.Username + " you have no registration.");
                    Thread.Sleep(1000);
                    SendToChat("/kick " + context.Received.Username + " not registered.");
                    Thread.Sleep(1000);

                    //I could process the request
                    return;
                }
            }
        }

        //I dont know what to do, continue with the next processor
        this.Successor.Process(context, command);
    }
}

每个命令都需要这些类之一。

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:

public class NewUserCommand : ConsoleCommand
{
    public override void Process(Context context, string command)
    {
        if (context.User != null)
        {
            // different greetings based on acess level
            if (context.Received.Message == "has entered this room")
            {
                if (context.User == null)
                {
                    SendToChat("/w " + context.Received.Username + " " + context.Received.Username + " you have no registration.");
                    Thread.Sleep(1000);
                    SendToChat("/kick " + context.Received.Username + " not registered.");
                    Thread.Sleep(1000);

                    //I could process the request
                    return;
                }
            }
        }

        //I dont know what to do, continue with the next processor
        this.Successor.Process(context, command);
    }
}

You will need one of these classes for every command.

隔纱相望 2024-11-17 06:25:01

我通常会使用一个小技巧,虽然这不是一个好的重构方法,但可以使代码更具可读性。

而不是:

if (condition1) {
    statement1;
} else if (condition2) {
    statement2;
    if (condition3) {
       statement3;
    }
}

... 我使用:

if (condition1) {
    statement1;
    return;
}

if (condition2) {
    statement;
    return;
}
if (condition2 && condition3) {
    statement3;
    return;
}

降低代码的复杂性是分解代码的第一步。我接下来要采取的步骤是:

  • 重构为不同的方法
  • 找到相似的方法,重构并使用辅助方法
  • 将不依赖于内部数据的方法移动到其他类
  • 当您似乎有两种不同的方法处理完全不同的“事物”时, ”,使它们成为单独的类(这是一项重大工作,特别是在冗长的代码上)
  • ,当您将事物分开但程序化时,您可能会开始应用模式来减少代码的重复。 Jason Down 提到了状态、策略,但是工厂、模板方法,其中大多数也可以,具体取决于您的需求。

I usually make a little trick that, while is not a good method of refactoring, makes the code more readable.

Instead of having:

if (condition1) {
    statement1;
} else if (condition2) {
    statement2;
    if (condition3) {
       statement3;
    }
}

... I use:

if (condition1) {
    statement1;
    return;
}

if (condition2) {
    statement;
    return;
}
if (condition2 && condition3) {
    statement3;
    return;
}

Reducing the complexity of the code is the first step to break it apart. Next steps in order for me to take are:

  • refactoring into different methods
  • finding similar methods, refactoring and having helper methods
  • moving methods that do not depend of internal data to other classes
  • when you seem to have two different methods that deal with complete different "things", make them separate classes (that's a major effort, specially on lengthy codes)
  • when you get things separated but procedural, you may start applying patterns that would make your code less repeated. Jason Down mentioned State, Strategy, but Factory, Template Method and most of them would also do, depending on your needs.
晨曦÷微暖 2024-11-17 06:25:01

它肯定需要一些重构。有几件事:

  • 不要重复自己 (fe Thread.Sleep(1000);
  • 将其分成几个方法
  • 将逻辑与构造分开。
  • 使用依赖注入(消息、isRunning 应传递给方法)。
  • 不要使用多个标志,而应使用多态性 - 很好的讨论

It definitely needs some refactoring. A few things:

梦初启 2024-11-17 06:25:01

好吧,一开始,我认为你应该将这个巨大的代码分成几个方法。将您评论过的逻辑部分分开。您应该为评论的每个部分使用一种方法(这是最少的)。尝试开始这个:

  1. Method: // SOME PARSED DATA HERE
    // if (parsedData matches) 执行以下操作
    尝试为此创建一种方法。

  2. Method // 获取发出命令的用户

  3. Method // 基于访问级别的不同问候语

  4. 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:

  1. Method: // SOME PARSED DATA HERE
    // if (parsedData matchs) do the below stuff
    Try to make one method of this.

  2. Method // Get the user that issued the command

  3. Method // different greetings based on acess level

  4. 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文