大型嵌套 switch 语句的设计模式

发布于 2024-11-18 18:28:12 字数 1415 浏览 1 评论 0原文

我搜索了许多有关重构大型 switch 语句的文章。

但他们没有做我想做的事。我要遇到的问题是有一个巨大的 switch 语句,它根据两个不同的值调用不同的方法,比如说一个 type 和一个 >代码。

目前,我会处理这样的情况:

switch (type)
{
    case Types.Type1:
        handleType1(code);
        break;

    case Types.Type2:
        handleType2(code);
        break;
}

void handleTypeN(code)
{
    switch (code)
    {
       ...
    }
}

也许结合工厂和命令模式的东西可以帮助我?我一定错过了一些明显的东西。

您将如何重构这段代码?


我可能需要更具体地了解我面临的情况。

我正在从服务器接收数据包。数据包包含类型和代码以及一些特定信息。

数据到达后,我会检索数据包的 typecode,并将其输入到 type 的 switch 语句中,在确定type之后,调用特定的方法来对数据包的code执行切换。

处理代码的方法现在进一步解码数据包并完成该过程。

+----------+                +----------+
|          |     Packet     |          |
|  Server  | -------------> |  Client  |
|          |                |          |
+----------+                +----------+
                                  |
                                  |
         (Switch on the type of the packet and call a specific method)
                                  |
                                  |
         (Switch on the code of the packet and call a specific method)
                                  |
                                  |
                    (Respond to the server or not)

I've searched for a number of articles on refactoring a large switch statement.

But they don't do what I want to do. The problem I'm going to to run in to is having a gigantic switch statement which calls a different method depending on two different values, lets say a type and a code.

Currently, I would handle the situation like this:

switch (type)
{
    case Types.Type1:
        handleType1(code);
        break;

    case Types.Type2:
        handleType2(code);
        break;
}

void handleTypeN(code)
{
    switch (code)
    {
       ...
    }
}

Maybe something which combines the factory and command pattern would help me out? I must be missing something obvious.

How would you refactor this code?


I might need to get a little more specific as to what scenario I'm facing.

I'm receiving packets from a server. A packet contains a type and a code and some specific information.

As soon as data arrives I retrieve the type and the code of the packet and it goes in to the switch statement for the type, after figuring out the type a specific method is called to perform a switch on the code of the packet.

The method that handles the code now decodes the packet further and the process is done.

+----------+                +----------+
|          |     Packet     |          |
|  Server  | -------------> |  Client  |
|          |                |          |
+----------+                +----------+
                                  |
                                  |
         (Switch on the type of the packet and call a specific method)
                                  |
                                  |
         (Switch on the code of the packet and call a specific method)
                                  |
                                  |
                    (Respond to the server or not)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(4

白衬杉格子梦 2024-11-25 18:28:12

想到了 2 种模式:命令和访客:
http://en.wikipedia.org/wiki/Command_pattern
http://en.wikipedia.org/wiki/Visitor_pattern

Abstract Class Command {

 executeSomething();

}
Class typeN extends command {

   executeSomething() {
    //...
   }
}

Class typeM extends command {

   executeSomething() {
    //...
   }
}

replace your switch by :
//my old switch
class commandManager {

processCommand() {
for listOf command in a command buffer
{ 
 onCommand(listOfcommand.command)
}
}
 onCommandPoped(command type) {
  type.executeSomething()
 }

}

you can pass parameters to executeSomething, and you can pass another command


the client code : 

{
 commandN = new CommandN()
 commandManager.postCommand( commandN)
}

阅读您的数据包服务器用例后,我认为您可以使用策略模式的变体
http://www.oodesign.com/strategy-pattern.html
您可以在其中选择数据包到达时调用的策略
你可以用工厂来建造这个。

但你不会杀死你的交换机

请记住,一个服务器可以为多个客户端提供服务。如果是的话,您的开关案例可能比对象实例化更快。

2 pattern comes in mind : command and visitor :
http://en.wikipedia.org/wiki/Command_pattern
http://en.wikipedia.org/wiki/Visitor_pattern

Abstract Class Command {

 executeSomething();

}
Class typeN extends command {

   executeSomething() {
    //...
   }
}

Class typeM extends command {

   executeSomething() {
    //...
   }
}

replace your switch by :
//my old switch
class commandManager {

processCommand() {
for listOf command in a command buffer
{ 
 onCommand(listOfcommand.command)
}
}
 onCommandPoped(command type) {
  type.executeSomething()
 }

}

you can pass parameters to executeSomething, and you can pass another command


the client code : 

{
 commandN = new CommandN()
 commandManager.postCommand( commandN)
}

After reading your packet server use case, I think you can use a variant of strategy pattern
http://www.oodesign.com/strategy-pattern.html
where you choose the strategy to call when the packet arrive
you can build this with a factory.

but you will not kill your switch case

Keep in mind, that a server can serve many client. If it's maybe your switch cases are faster than object instanciation.

花海 2024-11-25 18:28:12

我认为这取决于您想要进行什么样的代码改进。

如果您有能力实际进行重大设计更改,那么我建议多态性:

创建一个抽象 Packet 类。
为每种数据包类型创建一个类。
创建一个工厂方法,用于接收原始服务器数据包,并创建正确的数据包类对象。
每个数据包类类型都会有其自己所需完成的工作的实现。

如果您没有时间进行大型设计更改(通常是这种情况):

  • 如果您想提高可读性:

保留 switch,每个 switch case 将调用一个正确命名的函数,该函数将执行其需要的操作。

  • 如果您想提高性能:

创建一个矩阵,每个单元格 [T,C] 将保存对函数的引用,该函数将处理类型 T 和代码 C 的数据包。
矩阵应该在程序或类启动时启动一次(硬编码,没有办法解决)。
这将为您提供比长 switch 块更好的性能(直接访问代码,没有逻辑比较)

I think it depends what kind of code improvement you're trying to do.

If you have the luxury of actually making big design changes, then I'd suggest polymorphism:

Create an abstract Packet class.
Create a class for each packet type.
Create a factory method, that receives a raw server packet, and creates the right packet class object.
Each packet class type will have its own implementation of the job it needs to do.

If you don't have the luxury of doing large design changes (which is often the case):

  • If you want to improve readability :

Keep the switch, each switch case will call a properly named function that will do what it needs to.

  • If you want to increase performance:

Create a matrix, that for each cell [T,C] will hold a reference to a function that will handle a Packet with Type T and Code C.
The matrix should be initiated once (hard-coded, no way around that) at startup of program or class.
This will give you better performance than a long switch block (direct access to code, no logical comparisons)

潜移默化 2024-11-25 18:28:12

我将构建一个带有类型的表,该表指向带有代码的表,而该表又指向调用该类型/代码对的实现函数。

lookup_type_table[type_low .. type_high] = { lookup_code_table_type_1, lookup_code_table_type_2, ...};
lookup_code_table_type_1[type_1_code_low .. type_1_code_high] = { type1_code1_func_pointer, ... };

int processPacket(int type, int code, paket_t data) {
  /* apply boundary checks on the lookup tables here! */
  return lookup_type_table[type][code](data);
}

如果需要的话,这些表可以实现为链接列表,或者使用其他一些更高级的容器实现来使它们更加动态。

这可能不像其他一些模式那样面向对象,但我来自 C 背景 :)

将映射放在表中增加了从其他 DSL 规范生成它们的可能性,从而增强了 DRY 统计数据...

I'd build a table with types which points to tables with codes, which in turn points to the implementing function to call for that type/code pair.

lookup_type_table[type_low .. type_high] = { lookup_code_table_type_1, lookup_code_table_type_2, ...};
lookup_code_table_type_1[type_1_code_low .. type_1_code_high] = { type1_code1_func_pointer, ... };

int processPacket(int type, int code, paket_t data) {
  /* apply boundary checks on the lookup tables here! */
  return lookup_type_table[type][code](data);
}

The tables could be implemented as linked lists, or with some other fancier container implementation to make them more dynamic, if needed.

This might not be as object-oriented as some other patterns, but I'm coming from a C-background :)

Having the mappings in tables adds the possibility to generate them from some other DSL spec though, boosting your DRY stats...

⒈起吃苦の倖褔 2024-11-25 18:28:12

您可以用字典的字典替换您的开关,它指向实际的方法或更好的类来处理数据包。第一个字典使用类型作为索引,第二个字典使用代码作为索引。

但随后您将通过创建字典来替换 switch 语句,因此最终没有太大区别。

你也应该看看状态模式,这种东西才是它真正的用途。

You can replace your switches with a dictionary of dictionaries which points to the actual methods or better classes to handle the packets. The first dictionary using type as index and the second using code as index.

But then you will have replaced the switch statements by the creating of the dictionaries, so in the end there isn't much difference.

You should have a look to the state pattern too, this kind of stuff is what its actually made for.

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